diff --git a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java index ff5eaf223..eee8e6a40 100644 --- a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java +++ b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java @@ -312,18 +312,22 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment { mPasswordView.setText(password); } - if (Store.STORE_SCHEME_POP3.equals(recvAuth.mProtocol)) { - mLoadedDeletePolicy = account.getDeletePolicy(); - SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy); - } else if (Store.STORE_SCHEME_IMAP.equals(recvAuth.mProtocol)) { + if (Store.STORE_SCHEME_IMAP.equals(recvAuth.mProtocol)) { String prefix = recvAuth.mDomain; if (prefix != null && prefix.length() > 0) { mImapPathPrefixView.setText(prefix.substring(1)); } - } else { + } else if (!Store.STORE_SCHEME_POP3.equals(recvAuth.mProtocol)) { + // Account must either be IMAP or POP3 throw new Error("Unknown account type: " + account.getStoreUri(mContext)); } + // The delete policy is set for all legacy 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); + int flags = recvAuth.mFlags; flags &= ~HostAuth.FLAG_AUTHENTICATE; SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, flags); diff --git a/src/com/android/email/service/EmailBroadcastProcessorService.java b/src/com/android/email/service/EmailBroadcastProcessorService.java index 9d14ce97d..fd8801e0d 100644 --- a/src/com/android/email/service/EmailBroadcastProcessorService.java +++ b/src/com/android/email/service/EmailBroadcastProcessorService.java @@ -22,15 +22,24 @@ 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.widget.WidgetManager; import com.android.emailcommon.Logging; +import com.android.emailcommon.provider.EmailContent.Account; +import com.android.emailcommon.provider.EmailContent.AccountColumns; +import com.android.emailcommon.provider.EmailContent.HostAuth; 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; /** @@ -156,6 +165,12 @@ public class EmailBroadcastProcessorService extends IntentService { ExchangeUtils.enableEasCalendarSync(this); } + if (progress < 2) { + Log.i(Logging.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 @@ -167,6 +182,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, diff --git a/tests/src/com/android/email/service/EmailBroadcastProcessorServiceTests.java b/tests/src/com/android/email/service/EmailBroadcastProcessorServiceTests.java new file mode 100644 index 000000000..5b73d556e --- /dev/null +++ b/tests/src/com/android/email/service/EmailBroadcastProcessorServiceTests.java @@ -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.provider.ProviderTestUtils; +import com.android.emailcommon.provider.EmailContent.Account; +import com.android.emailcommon.provider.EmailContent.AccountColumns; +import com.android.emailcommon.provider.EmailContent.HostAuth; +import com.android.emailcommon.utility.Utility; + +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); + } + +}