From 463584d23f747cfbbd9856b39390269342363b41 Mon Sep 17 00:00:00 2001 From: Tony Mantler Date: Wed, 25 Sep 2013 14:47:13 -0700 Subject: [PATCH] Fix account matching at initial screen to match against email address b/10210901 Change-Id: I64d60ca33a42a19e085dd98a7a61d68ac30027f9 --- .../android/emailcommon/utility/Utility.java | 40 ++++++++++++++ .../setup/AccountServerBaseFragment.java | 52 +----------------- .../activity/setup/AccountSetupBasics.java | 34 +++++++----- .../setup/AccountSetupIncomingFragment.java | 6 +- .../setup/AccountSetupOutgoingFragment.java | 1 + .../activity/setup/AccountSetupType.java | 55 ++++++++++++++++++- 6 files changed, 117 insertions(+), 71 deletions(-) diff --git a/emailcommon/src/com/android/emailcommon/utility/Utility.java b/emailcommon/src/com/android/emailcommon/utility/Utility.java index e8259bd64..5bdcd11df 100644 --- a/emailcommon/src/com/android/emailcommon/utility/Utility.java +++ b/emailcommon/src/com/android/emailcommon/utility/Utility.java @@ -277,6 +277,46 @@ public class Utility { return null; } + /** + * This only actually matches against the email address. It's technically kosher to allow the + * same address across different account types, but that's a pretty rare use case and isn't well + * handled in the UI. + * + * @param context context + * @param syncAuthority the account manager type to check against or null for all types + * @param address email address to match against + * @return account name for match found or null + */ + public static String findExistingAccount(final Context context, final String syncAuthority, + final String address) { + final ContentResolver resolver = context.getContentResolver(); + final Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, + AccountColumns.EMAIL_ADDRESS + "=?", new String[] {address}, null); + try { + if (!c.moveToFirst()) { + return null; + } + return c.getString(c.getColumnIndex(Account.DISPLAY_NAME)); + /* + do { + if (syncAuthority != null) { + // TODO: actually compare the sync authority to allow creating the same account + // on different protocols. Sadly this code can't directly access the service info + } else { + final Account account = new Account(); + account.restore(c); + return account.mDisplayName; + } + } while (c.moveToNext()); + */ + } finally { + c.close(); + } + /* + return null; + */ + } + /** * Generate a random message-id header for locally-generated messages. */ diff --git a/src/com/android/email/activity/setup/AccountServerBaseFragment.java b/src/com/android/email/activity/setup/AccountServerBaseFragment.java index 254b036f3..dad261a4e 100644 --- a/src/com/android/email/activity/setup/AccountServerBaseFragment.java +++ b/src/com/android/email/activity/setup/AccountServerBaseFragment.java @@ -35,7 +35,6 @@ import com.android.email.R; import com.android.email.activity.UiUtilities; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.utility.Utility; /** * Common base class for server settings fragments, so they can be more easily manipulated by @@ -227,18 +226,6 @@ public abstract class AccountServerBaseFragment extends Fragment mCallback.onEnableProceedButtons(enable); } - /** - * Performs async operations as part of saving changes to the settings. - * Check for duplicate account - * Display dialog if necessary - * Else, proceed via mCallback.onProceedNext - */ - protected void startDuplicateTaskCheck(long accountId, String checkHost, String checkLogin, - int checkSettingsMode) { - new DuplicateCheckTask(accountId, checkHost, checkLogin, checkSettingsMode) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - /** * Make the given text view uneditable. If the text view is ever focused, the specified * error message will be displayed. @@ -304,47 +291,10 @@ public abstract class AccountServerBaseFragment extends Fragment /** * Clears the "next" button de-bounce flags and allows the "next" button to activate. */ - private void clearButtonBounce() { + protected void clearButtonBounce() { mProceedButtonPressed = false; } - private class DuplicateCheckTask extends AsyncTask { - - private final long mAccountId; - private final String mCheckHost; - private final String mCheckLogin; - private final int mCheckSettingsMode; - - public DuplicateCheckTask(long accountId, String checkHost, String checkLogin, - int checkSettingsMode) { - mAccountId = accountId; - mCheckHost = checkHost; - mCheckLogin = checkLogin; - mCheckSettingsMode = checkSettingsMode; - } - - @Override - protected Account doInBackground(Void... params) { - return Utility.findExistingAccount(mContext, mAccountId, mCheckHost, mCheckLogin); - } - - @Override - protected void onPostExecute(Account duplicateAccount) { - AccountServerBaseFragment fragment = AccountServerBaseFragment.this; - if (duplicateAccount != null) { - // Show duplicate account warning - final DuplicateAccountDialogFragment dialogFragment = - DuplicateAccountDialogFragment.newInstance(duplicateAccount.mDisplayName); - dialogFragment.show(fragment.getFragmentManager(), - DuplicateAccountDialogFragment.TAG); - } else { - // Otherwise, proceed with the save/check - mCallback.onProceedNext(mCheckSettingsMode, fragment); - } - clearButtonBounce(); - } - } - /** * Implements AccountCheckSettingsFragment.Callbacks * diff --git a/src/com/android/email/activity/setup/AccountSetupBasics.java b/src/com/android/email/activity/setup/AccountSetupBasics.java index eefc4522c..21d761d32 100644 --- a/src/com/android/email/activity/setup/AccountSetupBasics.java +++ b/src/com/android/email/activity/setup/AccountSetupBasics.java @@ -445,7 +445,8 @@ public class AccountSetupBasics extends AccountSetupActivity HostAuth.setHostAuthFromString(recvAuth, mProvider.incomingUri); recvAuth.setLogin(mProvider.incomingUsername, password); - final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(this, recvAuth.mProtocol); + final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(this, + recvAuth.mProtocol); recvAuth.mPort = ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) ? info.portSsl : info.port; @@ -458,7 +459,7 @@ public class AccountSetupBasics extends AccountSetupActivity // Stop here if the login credentials duplicate an existing account // Launch an Async task to do the work - new DuplicateCheckTask(this, recvAuth.mAddress, mProvider.incomingUsername, true) + new DuplicateCheckTask(this, email, true) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } catch (URISyntaxException e) { /* @@ -475,36 +476,34 @@ public class AccountSetupBasics extends AccountSetupActivity * Async task that continues the work of finishAutoSetup(). Checks for a duplicate * account and then either alerts the user, or continues. */ - private class DuplicateCheckTask extends AsyncTask { + private class DuplicateCheckTask extends AsyncTask { private final Context mContext; - private final String mCheckHost; - private final String mCheckLogin; + private final String mCheckAddress; private final boolean mAutoSetup; - public DuplicateCheckTask(Context context, String checkHost, String checkLogin, + public DuplicateCheckTask(Context context, String checkAddress, boolean autoSetup) { mContext = context; - mCheckHost = checkHost; - mCheckLogin = checkLogin; + mCheckAddress = checkAddress; // Prevent additional clicks on the next button during Async lookup mNextButtonInhibit = true; mAutoSetup = autoSetup; } @Override - protected Account doInBackground(Void... params) { - return Utility.findExistingAccount(mContext, -1, mCheckHost, mCheckLogin); + protected String doInBackground(Void... params) { + return Utility.findExistingAccount(mContext, null, mCheckAddress); } @Override - protected void onPostExecute(Account duplicateAccount) { + protected void onPostExecute(String duplicateAccountName) { mNextButtonInhibit = false; // Exit immediately if the user left before we finished if (mPaused) return; // Show duplicate account warning, or proceed - if (duplicateAccount != null) { + if (duplicateAccountName != null) { final DuplicateAccountDialogFragment dialogFragment = - DuplicateAccountDialogFragment.newInstance(duplicateAccount.mDisplayName); + DuplicateAccountDialogFragment.newInstance(duplicateAccountName); dialogFragment.show(getFragmentManager(), DuplicateAccountDialogFragment.TAG); } else { if (mAutoSetup) { @@ -520,6 +519,12 @@ public class AccountSetupBasics extends AccountSetupActivity } } } + + @Override + protected void onCancelled(String s) { + mNextButtonInhibit = false; + LogUtils.d(LogUtils.TAG, "DuplicateCheckTask cancelled (AccountSetupBasics)"); + } } /** @@ -529,7 +534,6 @@ public class AccountSetupBasics extends AccountSetupActivity // Try auto-configuration from XML providers (unless in EAS mode, we can skip it) final String email = mEmailView.getText().toString().trim(); final String[] emailParts = email.split("@"); - final String user = emailParts[0].trim(); final String domain = emailParts[1].trim(); mProvider = AccountSettingsUtils.findProviderForDomain(this, domain); if (mProvider != null) { @@ -543,7 +547,7 @@ public class AccountSetupBasics extends AccountSetupActivity } } else { // Can't use auto setup (although EAS accounts may still be able to AutoDiscover) - new DuplicateCheckTask(this, domain, user, false) + new DuplicateCheckTask(this, email, false) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } diff --git a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java index d63e3059a..af187a48e 100644 --- a/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java +++ b/src/com/android/email/activity/setup/AccountSetupIncomingFragment.java @@ -565,10 +565,8 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment recvAuth.mDomain = null; } - // Check for a duplicate account (requires async DB work) and if OK, - // proceed with check - startDuplicateTaskCheck( - account.mId, serverAddress, mCacheLoginCredential, SetupData.CHECK_INCOMING); + mCallback.onProceedNext(SetupData.CHECK_INCOMING, this); + clearButtonBounce(); } @Override diff --git a/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java b/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java index 4ed218622..a64f0ab1e 100644 --- a/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java +++ b/src/com/android/email/activity/setup/AccountSetupOutgoingFragment.java @@ -388,5 +388,6 @@ public class AccountSetupOutgoingFragment extends AccountServerBaseFragment sendAuth.mDomain = null; mCallback.onProceedNext(SetupData.CHECK_OUTGOING, this); + clearButtonBounce(); } } diff --git a/src/com/android/email/activity/setup/AccountSetupType.java b/src/com/android/email/activity/setup/AccountSetupType.java index 3bb7fd5b2..c40dcb5e1 100644 --- a/src/com/android/email/activity/setup/AccountSetupType.java +++ b/src/com/android/email/activity/setup/AccountSetupType.java @@ -18,6 +18,7 @@ package com.android.email.activity.setup; import android.app.Activity; import android.content.Intent; +import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -34,6 +35,8 @@ import com.android.email.service.EmailServiceUtils; import com.android.email.service.EmailServiceUtils.EmailServiceInfo; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.HostAuth; +import com.android.emailcommon.utility.Utility; +import com.android.mail.utils.LogUtils; /** * Prompts the user to select an account type. The account type, along with the @@ -42,6 +45,8 @@ import com.android.emailcommon.provider.HostAuth; */ public class AccountSetupType extends AccountSetupActivity implements OnClickListener { + private boolean mButtonPressed; + public static void actionSelectAccountType(Activity fromActivity, SetupData setupData) { final Intent i = new ForwardingIntent(fromActivity, AccountSetupType.class); i.putExtra(SetupData.EXTRA_SETUP_DATA, setupData); @@ -111,6 +116,15 @@ public class AccountSetupType extends AccountSetupActivity implements OnClickLis final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); recvAuth.setConnection(protocol, recvAuth.mAddress, recvAuth.mPort, recvAuth.mFlags); final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(this, protocol); + + new DuplicateCheckTask(account.mEmailAddress, info.accountType) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + private void onProceedNext() { + final Account account = mSetupData.getAccount(); + final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); + final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(this, recvAuth.mProtocol); if (info.usesAutodiscover) { mSetupData.setCheckSettingsMode(SetupData.CHECK_AUTODISCOVER); } else { @@ -131,8 +145,47 @@ public class AccountSetupType extends AccountSetupActivity implements OnClickLis finish(); break; default: - onSelect((String)v.getTag()); + if (!mButtonPressed) { + mButtonPressed = true; + onSelect((String)v.getTag()); + } break; } } + + private class DuplicateCheckTask extends AsyncTask { + private final String mAddress; + private final String mAuthority; + + public DuplicateCheckTask(String address, String authority) { + mAddress = address; + mAuthority = authority; + } + + @Override + protected String doInBackground(Void... params) { + return Utility.findExistingAccount(AccountSetupType.this, mAuthority, mAddress); + } + + @Override + protected void onPostExecute(String duplicateAccountName) { + mButtonPressed = false; + if (duplicateAccountName != null) { + // Show duplicate account warning + final DuplicateAccountDialogFragment dialogFragment = + DuplicateAccountDialogFragment.newInstance(duplicateAccountName); + dialogFragment.show(AccountSetupType.this.getFragmentManager(), + DuplicateAccountDialogFragment.TAG); + } else { + // Otherwise, proceed with the save/check + onProceedNext(); + } + } + + @Override + protected void onCancelled(String s) { + mButtonPressed = false; + LogUtils.d(LogUtils.TAG, "Duplicate account check cancelled (AccountSetupType)"); + } + } }