From 926e7369d114f5747a81710987500ff407fba964 Mon Sep 17 00:00:00 2001 From: Andy Stadler Date: Sat, 25 Dec 2010 23:16:10 -0800 Subject: [PATCH] Remove UI thread disk access from AccountSetupNames * Remove unneeded DB read in onCreate (add runtime checks for problems) * Move more exit/commit work to existing AsyncTask * Add lockout of next & back keys while processing Bug: 2792509 (probably others) Change-Id: I0db030a1f1df94ba721510b5112519f260f5c0f9 --- .../activity/setup/AccountSetupNames.java | 114 ++++++++++-------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/src/com/android/email/activity/setup/AccountSetupNames.java b/src/com/android/email/activity/setup/AccountSetupNames.java index 21fce51c8..d8a0a37be 100644 --- a/src/com/android/email/activity/setup/AccountSetupNames.java +++ b/src/com/android/email/activity/setup/AccountSetupNames.java @@ -23,10 +23,10 @@ import com.android.email.activity.ActivityHelper; import com.android.email.activity.Welcome; import com.android.email.provider.EmailContent.Account; import com.android.email.provider.EmailContent.AccountColumns; -import com.android.email.provider.EmailContent.HostAuth; import android.app.Activity; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; @@ -39,16 +39,20 @@ import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; +/** + * Final screen of setup process. Collect account nickname and/or username. + * + * TODO: Better processing of account nickname including trimming and prevention of empty string. + */ public class AccountSetupNames extends AccountSetupActivity implements OnClickListener { private static final int REQUEST_SECURITY = 0; private EditText mDescription; private EditText mName; private Button mNextButton; + private boolean mNextPressed = false; private boolean mEasAccount = false; - private CheckAccountStateTask mCheckAccountStateTask; - public static void actionSetNames(Activity fromActivity) { fromActivity.startActivity(new Intent(fromActivity, AccountSetupNames.class)); } @@ -78,20 +82,15 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi mName.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS)); Account account = SetupData.getAccount(); - // Shouldn't happen, but it could if (account == null) { - onBackPressed(); - return; + throw new IllegalStateException("unexpected null account"); } - // Get the hostAuth for receiving - HostAuth hostAuth = HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv); - if (hostAuth == null) { - onBackPressed(); - return; + if (account.mHostAuthRecv == null) { + throw new IllegalStateException("unexpected null hostauth"); } // Remember whether we're an EAS account, since it doesn't require the user name field - mEasAccount = hostAuth.mProtocol.equals("eas"); + mEasAccount = "eas".equals(account.mHostAuthRecv.mProtocol); if (mEasAccount) { mName.setVisibility(View.GONE); findViewById(R.id.account_name_label).setVisibility(View.GONE); @@ -115,17 +114,6 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi } } - @Override - protected void onDestroy() { - super.onDestroy(); - - if (mCheckAccountStateTask != null && - mCheckAccountStateTask.getStatus() != CheckAccountStateTask.Status.FINISHED) { - mCheckAccountStateTask.cancel(true); - mCheckAccountStateTask = null; - } - } - /** * Implements OnClickListener */ @@ -133,21 +121,36 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi public void onClick(View v) { switch (v.getId()) { case R.id.next: - onNext(); + // Don't allow this more than once (we do some work in an async thread before + // finish()'ing the Activity, which allows this code to potentially be + // executed multiple times. + if (!mNextPressed) { + onNext(); + } + mNextPressed = true; break; } } /** - * TODO: Validator should also trim the name string before checking it. + * Check input fields for legal values and enable/disable next button */ private void validateFields() { boolean newEnabled = mEasAccount || Utility.isTextViewNotEmpty(mName); mNextButton.setEnabled(newEnabled); } + /** + * Block the back key if we are currently processing the "next" key" + */ @Override public void onBackPressed() { + if (!mNextPressed) { + finishActivity(); + } + } + + private void finishActivity() { if (SetupData.getFlowMode() != SetupData.FLOW_MODE_NORMAL) { AccountSetupBasics.actionAccountCreateFinishedAccountFlow(this); } else { @@ -164,53 +167,58 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi } /** - * After having a chance to input the display names, we normally jump directly to the - * inbox for the new account. However if we're in EAS flow mode (externally-launched - * account creation) we simply "pop" here which should return us to the Accounts activities. - * - * TODO: Validator should also trim the description string before checking it. + * After clicking the next button, we'll start an async task to commit the data + * and other steps to finish the creation of the account. */ private void onNext() { + // Update account object from UI Account account = SetupData.getAccount(); if (Utility.isTextViewNotEmpty(mDescription)) { account.setDisplayName(mDescription.getText().toString()); } - String name = mName.getText().toString(); - account.setSenderName(name); - ContentValues cv = new ContentValues(); - cv.put(AccountColumns.DISPLAY_NAME, account.getDisplayName()); - cv.put(AccountColumns.SENDER_NAME, name); - account.update(this, cv); - // Update the backup (side copy) of the accounts - AccountBackupRestore.backupAccounts(this); + account.setSenderName(mName.getText().toString()); - // Before proceeding, launch an AsyncTask to test the account for any syncing problems, - // and if there's a problem, bring up the UI to update the security level. - mCheckAccountStateTask = new CheckAccountStateTask(account.mId); - mCheckAccountStateTask.execute(); + // Launch async task for final commit work + new FinalSetupTask(account).execute(); } /** - * This async task is launched just before exiting. It's a last chance test, before leaving - * this activity, for the account being in a "hold" state, and gives the user a chance to - * update security, enter a device PIN, etc. for a more seamless account setup experience. + * Final account setup work is handled in this AsyncTask: + * Commit final values to provider + * Trigger account backup + * Check for security hold + * + * When this completes, we return to UI thread for the following steps: + * If security hold, dispatch to AccountSecurity activity + * Otherwise, return to AccountSetupBasics for conclusion. * * TODO: If there was *any* indication that security might be required, we could at least * force the DeviceAdmin activation step, without waiting for the initial sync/handshake * to fail. * TODO: If the user doesn't update the security, don't go to the MessageList. */ - private class CheckAccountStateTask extends AsyncTask { + private class FinalSetupTask extends AsyncTask { - private long mAccountId; + private Account mAccount; + private Context mContext; - public CheckAccountStateTask(long accountId) { - mAccountId = accountId; + public FinalSetupTask(Account account) { + mAccount = account; + mContext = AccountSetupNames.this; } @Override protected Boolean doInBackground(Void... params) { - return Account.isSecurityHold(AccountSetupNames.this, mAccountId); + // Update the account in the database + ContentValues cv = new ContentValues(); + cv.put(AccountColumns.DISPLAY_NAME, mAccount.getDisplayName()); + cv.put(AccountColumns.SENDER_NAME, mAccount.getSenderName()); + mAccount.update(mContext, cv); + + // Update the backup (side copy) of the accounts + AccountBackupRestore.backupAccounts(AccountSetupNames.this); + + return Account.isSecurityHold(mContext, mAccount.mId); } @Override @@ -218,10 +226,10 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi if (!isCancelled()) { if (isSecurityHold) { Intent i = AccountSecurity.actionUpdateSecurityIntent( - AccountSetupNames.this, mAccountId); + AccountSetupNames.this, mAccount.mId); AccountSetupNames.this.startActivityForResult(i, REQUEST_SECURITY); } else { - onBackPressed(); + finishActivity(); } } } @@ -236,7 +244,7 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_SECURITY: - onBackPressed(); + finishActivity(); } super.onActivityResult(requestCode, resultCode, data); }