DO NOT MERGE: Backport fix for IMAP delete bug

Original CL comment:
Always set a delete policy for legacy accounts

The delete policy can only be set for POP3 accounts. However, the delete
policy is used for all legacy accounts (that includes IMAP). As such, we
need to make sure IMAP accounts also have their policy set; even though
the setting is not configurable by the user.

The delete policy does not mean anything for Exchange accounts, so, we do
not need to modify the account setup code for them.

bug 3074164
Original Change-Id: Iab10d2997404b3b0c10a60a64fb652540c0d2d1a

Change-Id: Idc290aa1b8ff4f17a0c8fd57333523becef0c8e5
This commit is contained in:
Andy Stadler 2011-02-28 15:24:05 -08:00
parent 66d4a38050
commit 067c874c31
3 changed files with 191 additions and 5 deletions

View File

@ -20,6 +20,7 @@ import com.android.email.AccountBackupRestore;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
@ -334,17 +335,21 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
mPasswordView.setText(password);
}
if (uri.getScheme().startsWith("pop3")) {
mLoadedDeletePolicy = account.getDeletePolicy();
SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy);
} else if (uri.getScheme().startsWith("imap")) {
if (uri.getScheme().startsWith(Store.STORE_SCHEME_IMAP)) {
if (uri.getPath() != null && uri.getPath().length() > 0) {
mImapPathPrefixView.setText(uri.getPath().substring(1));
}
} else {
} else if (!uri.getScheme().startsWith(Store.STORE_SCHEME_POP3)) {
// Account must either be IMAP or POP3
throw new Error("Unknown account type: " + account.getStoreUri(mContext));
}
// The delete policy is set for all accounts. For POP3 accounts, the user sets
// the policy explicitly. For IMAP accounts, the policy is set when the Account object
// is created. @see AccountSetupBasics#populateSetupData
mLoadedDeletePolicy = account.getDeletePolicy();
SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy);
for (int i = 0; i < mAccountSchemes.length; i++) {
if (mAccountSchemes[i].equals(uri.getScheme())) {
SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i);

View File

@ -22,14 +22,23 @@ import com.android.email.Preferences;
import com.android.email.SecurityPolicy;
import com.android.email.VendorPolicyLoader;
import com.android.email.activity.setup.AccountSettingsXL;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.HostAuth;
import com.android.email.provider.WidgetProvider;
import android.accounts.AccountManager;
import android.app.IntentService;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
/**
@ -155,6 +164,12 @@ public class EmailBroadcastProcessorService extends IntentService {
ExchangeUtils.enableEasCalendarSync(this);
}
if (progress < 2) {
Log.i(Email.LOG_TAG, "Onetime initialization: 2");
progress = 2;
setImapDeletePolicy(this);
}
// Add your initialization steps here.
// Use "progress" to skip the initializations that's already done before.
// Using this preference also makes it safe when a user skips an upgrade. (i.e. upgrading
@ -166,6 +181,34 @@ public class EmailBroadcastProcessorService extends IntentService {
}
}
/**
* Sets the delete policy to the correct value for all IMAP accounts. This will have no
* effect on either EAS or POP3 accounts.
*/
/*package*/ static void setImapDeletePolicy(Context context) {
ContentResolver resolver = context.getContentResolver();
Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
null, null, null);
try {
while (c.moveToNext()) {
long recvAuthKey = c.getLong(Account.CONTENT_HOST_AUTH_KEY_RECV_COLUMN);
HostAuth recvAuth = HostAuth.restoreHostAuthWithId(context, recvAuthKey);
if (Store.STORE_SCHEME_IMAP.equals(recvAuth.mProtocol)) {
int flags = c.getInt(Account.CONTENT_FLAGS_COLUMN);
flags &= ~Account.FLAGS_DELETE_POLICY_MASK;
flags |= Account.DELETE_POLICY_ON_DELETE << Account.FLAGS_DELETE_POLICY_SHIFT;
ContentValues cv = new ContentValues();
cv.put(AccountColumns.FLAGS, flags);
long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId);
resolver.update(uri, cv, null, null);
}
}
} finally {
c.close();
}
}
private void setComponentEnabled(Class<?> clazz, boolean enabled) {
final ComponentName c = new ComponentName(this, clazz.getName());
getPackageManager().setComponentEnabledSetting(c,

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.service;
import com.android.email.AccountTestCase;
import com.android.email.Utility;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.HostAuth;
import com.android.email.provider.ProviderTestUtils;
import android.content.ContentUris;
import android.content.Context;
import android.net.Uri;
import java.util.NoSuchElementException;
/**
* Tests of the Email provider.
*
* You can run this entire test case with:
* runtest -c com.android.email.service.EmailBroadcastProcessorServiceTests email
*/
public class EmailBroadcastProcessorServiceTests extends AccountTestCase {
Context mMockContext;
public EmailBroadcastProcessorServiceTests() {
super();
}
@Override
public void setUp() throws Exception {
super.setUp();
mMockContext = getMockContext();
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
/**
* Create a simple HostAuth with protocol
*/
private HostAuth setupSimpleHostAuth(String protocol) {
HostAuth hostAuth = ProviderTestUtils.setupHostAuth(protocol, "name", 1L, false, mContext);
hostAuth.mProtocol = protocol;
return hostAuth;
}
/**
* Returns the flags for the specified account. Throws an exception if the account cannot
* be found.
*/
private int getAccountFlags(long accountId) throws NoSuchElementException {
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId);
Integer flags = Utility.getFirstRowInt(mMockContext, uri,
new String[] { AccountColumns.FLAGS }, null, null, null, 0);
if (flags == null) {
throw new NoSuchElementException("No cursor");
}
return flags;
}
/**
* Initial testing on setupSyncReportsLocked, making sure that EAS accounts aren't scheduled
*/
public void testSetImapDeletePolicy() {
// Setup accounts of each type, all with manual sync at different intervals
Account account1 = ProviderTestUtils.setupAccount("eas-account1", false, mMockContext);
account1.mHostAuthRecv = setupSimpleHostAuth("eas");
account1.mHostAuthSend = account1.mHostAuthRecv;
account1.save(mMockContext);
long accountId1 = account1.mId;
Account account2 = ProviderTestUtils.setupAccount("pop-account1", false, mMockContext);
account2.mHostAuthRecv = setupSimpleHostAuth("pop3");
account2.mHostAuthSend = setupSimpleHostAuth("smtp");
account2.mFlags = 0x08; // set delete policy
account2.save(mMockContext);
long accountId2 = account2.mId;
Account account3 = ProviderTestUtils.setupAccount("pop-account2", false, mMockContext);
account3.mHostAuthRecv = setupSimpleHostAuth("pop3");
account3.mHostAuthSend = setupSimpleHostAuth("smtp");
account3.save(mMockContext);
long accountId3 = account3.mId;
Account account4 = ProviderTestUtils.setupAccount("imap-account1", false, mMockContext);
account4.mHostAuthRecv = setupSimpleHostAuth("imap");
account4.mHostAuthSend = setupSimpleHostAuth("smtp");
account4.mFlags = 0xa5a5a5a5; // Alternating bits; includes bad delete policy
account4.save(mMockContext);
long accountId4 = account4.mId;
Account account5 = ProviderTestUtils.setupAccount("imap-account2", false, mMockContext);
account5.mHostAuthRecv = setupSimpleHostAuth("imap");
account5.mHostAuthSend = setupSimpleHostAuth("smtp");
account5.mFlags = 0x0c; // All delete policy bits set
account5.save(mMockContext);
long accountId5 = account5.mId;
Account account6 = ProviderTestUtils.setupAccount("imap-account3", false, mMockContext);
account6.mHostAuthRecv = setupSimpleHostAuth("imap");
account6.mHostAuthSend = setupSimpleHostAuth("smtp");
account6.mFlags = 0; // No delete policy bits set
account6.save(mMockContext);
long accountId6 = account6.mId;
// Run the account migration
EmailBroadcastProcessorService.setImapDeletePolicy(mMockContext);
// Test the results
int accountFlags1 = getAccountFlags(accountId1);
assertEquals(4, accountFlags1); // not IMAP; no changes
int accountFlags2 = getAccountFlags(accountId2);
assertEquals(8, accountFlags2); // not IMAP; no changes
int accountFlags3 = getAccountFlags(accountId3);
assertEquals(4, accountFlags3); // not IMAP; no changes
int accountFlags4 = getAccountFlags(accountId4);
assertEquals(0xa5a5a5a9, accountFlags4); // Only update delete policy bits
int accountFlags5 = getAccountFlags(accountId5);
assertEquals(0x00000008, accountFlags5);
int accountFlags6 = getAccountFlags(accountId6);
assertEquals(0x00000008, accountFlags6);
}
}