| /* |
| * Copyright (C) 2014 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.activity.setup; |
| |
| import android.accounts.AccountAuthenticatorResponse; |
| import android.accounts.AccountManager; |
| import android.app.ActionBar; |
| import android.app.ActivityManager; |
| import android.app.AlertDialog; |
| import android.app.Dialog; |
| import android.app.DialogFragment; |
| import android.app.Fragment; |
| import android.app.FragmentManager; |
| import android.app.FragmentTransaction; |
| import android.app.LoaderManager; |
| import android.app.ProgressDialog; |
| import android.content.Context; |
| import android.content.CursorLoader; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.Loader; |
| import android.database.Cursor; |
| import android.os.Bundle; |
| import android.provider.ContactsContract; |
| import androidx.annotation.NonNull; |
| import android.text.TextUtils; |
| import android.view.View; |
| import android.view.inputmethod.InputMethodManager; |
| import android.widget.Toast; |
| |
| import com.android.email.R; |
| import com.android.email.setup.AuthenticatorSetupIntentHelper; |
| import com.android.email.service.EmailServiceUtils; |
| import com.android.emailcommon.VendorPolicyLoader; |
| import com.android.emailcommon.provider.Account; |
| import com.android.emailcommon.provider.HostAuth; |
| import com.android.emailcommon.service.SyncWindow; |
| import com.android.mail.analytics.Analytics; |
| import com.android.mail.providers.MailAppProvider; |
| import com.android.mail.providers.UIProvider; |
| import com.android.mail.utils.LogUtils; |
| |
| import java.net.URISyntaxException; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| public class AccountSetupFinal extends AccountSetupActivity |
| implements AccountFinalizeFragment.Callback, |
| AccountSetupNoteDialogFragment.Callback, AccountCreationFragment.Callback, |
| AccountCheckSettingsFragment.Callback, SecurityRequiredDialogFragment.Callback, |
| CheckSettingsErrorDialogFragment.Callback, CheckSettingsProgressDialogFragment.Callback, |
| AccountSetupTypeFragment.Callback, AccountSetupNamesFragment.Callback, |
| AccountSetupOptionsFragment.Callback, AccountSetupBasicsFragment.Callback, |
| AccountServerBaseFragment.Callback, AccountSetupCredentialsFragment.Callback, |
| DuplicateAccountDialogFragment.Callback, AccountSetupABFragment.Callback { |
| |
| /** |
| * Direct access for forcing account creation |
| * For use by continuous automated test system (e.g. in conjunction with monkey tests) |
| * |
| * === Support for automated testing == |
| * This activity can also be launched directly via INTENT_FORCE_CREATE_ACCOUNT. This is intended |
| * only for use by continuous test systems, and is currently only available when |
| * {@link ActivityManager#isRunningInTestHarness()} is set. To use this mode, you must |
| * construct an intent which contains all necessary information to create the account. No |
| * connection checking is done, so the account may or may not actually work. Here is a sample |
| * command, for a gmail account "test_account" with a password of "test_password". |
| * |
| * $ adb shell am start -a com.android.email.FORCE_CREATE_ACCOUNT \ |
| * -e EMAIL test_account@gmail.com \ |
| * -e USER "Test Account Name" \ |
| * -e INCOMING imap+ssl+://test_account:test_password@imap.gmail.com \ |
| * -e OUTGOING smtp+ssl+://test_account:test_password@smtp.gmail.com |
| * |
| * Note: For accounts that require the full email address in the login, encode the @ as %40. |
| * Note: Exchange accounts that require device security policies cannot be created |
| * automatically. |
| * |
| * For accounts that correspond to services in providers.xml you can also use the following form |
| * |
| * $adb shell am start -a com.android.email.FORCE_CREATE_ACCOUNT \ |
| * -e EMAIL test_account@gmail.com \ |
| * -e PASSWORD test_password |
| * |
| * and the appropriate incoming/outgoing information will be filled in automatically. |
| */ |
| private static String INTENT_FORCE_CREATE_ACCOUNT; |
| private static final String EXTRA_CREATE_ACCOUNT_EMAIL = "EMAIL"; |
| private static final String EXTRA_CREATE_ACCOUNT_USER = "USER"; |
| private static final String EXTRA_CREATE_ACCOUNT_PASSWORD = "PASSWORD"; |
| private static final String EXTRA_CREATE_ACCOUNT_INCOMING = "INCOMING"; |
| private static final String EXTRA_CREATE_ACCOUNT_OUTGOING = "OUTGOING"; |
| private static final String EXTRA_CREATE_ACCOUNT_SYNC_LOOKBACK = "SYNC_LOOKBACK"; |
| |
| private static final String CREATE_ACCOUNT_SYNC_ALL_VALUE = "ALL"; |
| |
| private static final Boolean DEBUG_ALLOW_NON_TEST_HARNESS_CREATION = false; |
| |
| protected static final String ACTION_JUMP_TO_INCOMING = "jumpToIncoming"; |
| protected static final String ACTION_JUMP_TO_OUTGOING = "jumpToOutgoing"; |
| protected static final String ACTION_JUMP_TO_OPTIONS = "jumpToOptions"; |
| |
| private static final String SAVESTATE_KEY_IS_PROCESSING = "AccountSetupFinal.is_processing"; |
| private static final String SAVESTATE_KEY_STATE = "AccountSetupFinal.state"; |
| private static final String SAVESTATE_KEY_PROVIDER = "AccountSetupFinal.provider"; |
| private static final String SAVESTATE_KEY_AUTHENTICATOR_RESPONSE = "AccountSetupFinal.authResp"; |
| private static final String SAVESTATE_KEY_REPORT_AUTHENTICATOR_ERROR = |
| "AccountSetupFinal.authErr"; |
| private static final String SAVESTATE_KEY_IS_PRE_CONFIGURED = "AccountSetupFinal.preconfig"; |
| private static final String SAVESTATE_KEY_SKIP_AUTO_DISCOVER = "AccountSetupFinal.noAuto"; |
| private static final String SAVESTATE_KEY_PASSWORD_FAILED = "AccountSetupFinal.passwordFailed"; |
| |
| private static final String CONTENT_FRAGMENT_TAG = "AccountSetupContentFragment"; |
| private static final String CREDENTIALS_BACKSTACK_TAG = "AccountSetupCredentialsFragment"; |
| |
| // Collecting initial email and password |
| private static final int STATE_BASICS = 0; |
| // Show the user some interstitial message after email entry |
| private static final int STATE_BASICS_POST = 1; |
| // Account is not pre-configured, query user for account type |
| private static final int STATE_TYPE = 2; |
| // Account is pre-configured, but the user picked a different protocol |
| private static final int STATE_AB = 3; |
| // Collect initial password or oauth token |
| private static final int STATE_CREDENTIALS = 4; |
| // Account is a pre-configured account, run the checker |
| private static final int STATE_CHECKING_PRECONFIGURED = 5; |
| // Auto-discovering exchange account info, possibly other protocols later |
| private static final int STATE_AUTO_DISCOVER = 6; |
| // User is entering incoming settings |
| private static final int STATE_MANUAL_INCOMING = 7; |
| // We're checking incoming settings |
| private static final int STATE_CHECKING_INCOMING = 8; |
| // User is entering outgoing settings |
| private static final int STATE_MANUAL_OUTGOING = 9; |
| // We're checking outgoing settings |
| private static final int STATE_CHECKING_OUTGOING = 10; |
| // User is entering sync options |
| private static final int STATE_OPTIONS = 11; |
| // We're creating the account |
| private static final int STATE_CREATING = 12; |
| // User is entering account name and real name |
| private static final int STATE_NAMES = 13; |
| // we're finalizing the account |
| private static final int STATE_FINALIZE = 14; |
| |
| private int mState = STATE_BASICS; |
| |
| private boolean mIsProcessing = false; |
| private boolean mForceCreate = false; |
| private boolean mReportAccountAuthenticatorError; |
| private AccountAuthenticatorResponse mAccountAuthenticatorResponse; |
| // True if this provider is found in our providers.xml, set after Basics |
| private boolean mIsPreConfiguredProvider = false; |
| // True if the user selected manual setup |
| private boolean mSkipAutoDiscover = false; |
| // True if validating the pre-configured provider failed and we want manual setup |
| private boolean mPreConfiguredFailed = false; |
| |
| private VendorPolicyLoader.Provider mProvider; |
| private boolean mPasswordFailed; |
| |
| private static final int OWNER_NAME_LOADER_ID = 0; |
| private String mOwnerName; |
| |
| private static final int EXISTING_ACCOUNTS_LOADER_ID = 1; |
| private Map<String, String> mExistingAccountsMap; |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| final Intent intent = getIntent(); |
| final String action = intent.getAction(); |
| |
| if (INTENT_FORCE_CREATE_ACCOUNT == null) { |
| INTENT_FORCE_CREATE_ACCOUNT = getString(R.string.intent_force_create_email_account); |
| } |
| |
| setContentView(R.layout.account_setup_activity); |
| |
| final ActionBar actionBar = getActionBar(); |
| if (actionBar != null) { |
| // Hide the app icon. |
| actionBar.setIcon(android.R.color.transparent); |
| actionBar.setDisplayUseLogoEnabled(false); |
| } |
| |
| if (savedInstanceState != null) { |
| mIsProcessing = savedInstanceState.getBoolean(SAVESTATE_KEY_IS_PROCESSING, false); |
| mState = savedInstanceState.getInt(SAVESTATE_KEY_STATE, STATE_OPTIONS); |
| mProvider = (VendorPolicyLoader.Provider) |
| savedInstanceState.getSerializable(SAVESTATE_KEY_PROVIDER); |
| mAccountAuthenticatorResponse = |
| savedInstanceState.getParcelable(SAVESTATE_KEY_AUTHENTICATOR_RESPONSE); |
| mReportAccountAuthenticatorError = |
| savedInstanceState.getBoolean(SAVESTATE_KEY_REPORT_AUTHENTICATOR_ERROR); |
| mIsPreConfiguredProvider = |
| savedInstanceState.getBoolean(SAVESTATE_KEY_IS_PRE_CONFIGURED); |
| mSkipAutoDiscover = savedInstanceState.getBoolean(SAVESTATE_KEY_SKIP_AUTO_DISCOVER); |
| mPasswordFailed = savedInstanceState.getBoolean(SAVESTATE_KEY_PASSWORD_FAILED); |
| } else { |
| // If we're not restoring from a previous state, we want to configure the initial screen |
| |
| // Set aside incoming AccountAuthenticatorResponse, if there was any |
| mAccountAuthenticatorResponse = getIntent() |
| .getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE); |
| if (mAccountAuthenticatorResponse != null) { |
| // When this Activity is called as part of account authentification flow, |
| // we are responsible for eventually reporting the result (success or failure) to |
| // the account manager. Most exit paths represent an failed or abandoned setup, |
| // so the default is to report the error. Success will be reported by the code in |
| // AccountSetupOptions that commits the finally created account. |
| mReportAccountAuthenticatorError = true; |
| } |
| |
| // Initialize the SetupDataFragment |
| if (INTENT_FORCE_CREATE_ACCOUNT.equals(action)) { |
| mSetupData.setFlowMode(AuthenticatorSetupIntentHelper.FLOW_MODE_FORCE_CREATE); |
| } else { |
| final int intentFlowMode = intent.getIntExtra( |
| AuthenticatorSetupIntentHelper.EXTRA_FLOW_MODE, |
| AuthenticatorSetupIntentHelper.FLOW_MODE_UNSPECIFIED); |
| final String flowAccountType = intent.getStringExtra( |
| AuthenticatorSetupIntentHelper.EXTRA_FLOW_ACCOUNT_TYPE); |
| mSetupData.setAmProtocol( |
| EmailServiceUtils.getProtocolFromAccountType(this, flowAccountType)); |
| mSetupData.setFlowMode(intentFlowMode); |
| } |
| |
| mState = STATE_BASICS; |
| // Support unit testing individual screens |
| if (TextUtils.equals(ACTION_JUMP_TO_INCOMING, action)) { |
| mState = STATE_MANUAL_INCOMING; |
| } else if (TextUtils.equals(ACTION_JUMP_TO_OUTGOING, action)) { |
| mState = STATE_MANUAL_OUTGOING; |
| } else if (TextUtils.equals(ACTION_JUMP_TO_OPTIONS, action)) { |
| mState = STATE_OPTIONS; |
| } |
| updateContentFragment(false /* addToBackstack */); |
| mPasswordFailed = false; |
| } |
| |
| if (!mIsProcessing && mSetupData.getFlowMode() == |
| AuthenticatorSetupIntentHelper.FLOW_MODE_FORCE_CREATE) { |
| /** |
| * To support continuous testing, we allow the forced creation of accounts. |
| * This works in a manner fairly similar to automatic setup, in which the complete |
| * server Uri's are available, except that we will also skip checking (as if both |
| * checks were true) and all other UI. |
| * |
| * email: The email address for the new account |
| * user: The user name for the new account |
| * incoming: The URI-style string defining the incoming account |
| * outgoing: The URI-style string defining the outgoing account |
| */ |
| final String email = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_EMAIL); |
| final String user = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_USER); |
| final String password = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_PASSWORD); |
| final String incoming = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_INCOMING); |
| final String outgoing = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_OUTGOING); |
| final String syncLookbackText = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_SYNC_LOOKBACK); |
| final int syncLookback; |
| if (TextUtils.equals(syncLookbackText, CREATE_ACCOUNT_SYNC_ALL_VALUE)) { |
| syncLookback = SyncWindow.SYNC_WINDOW_ALL; |
| } else { |
| syncLookback = -1; |
| } |
| // If we've been explicitly provided with all the details to fill in the account, we |
| // can use them |
| final boolean explicitForm = !(TextUtils.isEmpty(user) || |
| TextUtils.isEmpty(incoming) || TextUtils.isEmpty(outgoing)); |
| // If we haven't been provided the details, but we have the password, we can look up |
| // the info from providers.xml |
| final boolean implicitForm = !TextUtils.isEmpty(password) && !explicitForm; |
| if (TextUtils.isEmpty(email) || !(explicitForm || implicitForm)) { |
| LogUtils.e(LogUtils.TAG, "Force account create requires extras EMAIL, " + |
| "USER, INCOMING, OUTGOING, or EMAIL and PASSWORD"); |
| finish(); |
| return; |
| } |
| |
| if (implicitForm) { |
| final String[] emailParts = email.split("@"); |
| final String domain = emailParts[1].trim(); |
| mProvider = AccountSettingsUtils.findProviderForDomain(this, domain); |
| if (mProvider == null) { |
| LogUtils.e(LogUtils.TAG, "findProviderForDomain couldn't find provider"); |
| finish(); |
| return; |
| } |
| mIsPreConfiguredProvider = true; |
| mSetupData.setEmail(email); |
| boolean autoSetupCompleted = finishAutoSetup(); |
| if (!autoSetupCompleted) { |
| LogUtils.e(LogUtils.TAG, "Force create account failed to create account"); |
| finish(); |
| return; |
| } |
| final Account account = mSetupData.getAccount(); |
| final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); |
| recvAuth.mPassword = password; |
| final HostAuth sendAuth = account.getOrCreateHostAuthSend(this); |
| sendAuth.mPassword = password; |
| } else { |
| final Account account = mSetupData.getAccount(); |
| |
| try { |
| final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); |
| recvAuth.setHostAuthFromString(incoming); |
| |
| final HostAuth sendAuth = account.getOrCreateHostAuthSend(this); |
| sendAuth.setHostAuthFromString(outgoing); |
| } catch (URISyntaxException e) { |
| // If we can't set up the URL, don't continue |
| Toast.makeText(this, R.string.account_setup_username_password_toast, |
| Toast.LENGTH_LONG) |
| .show(); |
| finish(); |
| return; |
| } |
| |
| populateSetupData(user, email); |
| // We need to do this after calling populateSetupData(), because that will |
| // overwrite it with the default values. |
| if (syncLookback >= SyncWindow.SYNC_WINDOW_ACCOUNT && |
| syncLookback <= SyncWindow.SYNC_WINDOW_ALL) { |
| account.mSyncLookback = syncLookback; |
| } |
| } |
| |
| mState = STATE_OPTIONS; |
| updateContentFragment(false /* addToBackstack */); |
| getFragmentManager().executePendingTransactions(); |
| |
| if (!DEBUG_ALLOW_NON_TEST_HARNESS_CREATION && |
| !ActivityManager.isRunningInTestHarness()) { |
| LogUtils.e(LogUtils.TAG, |
| "ERROR: Force account create only allowed while in test harness"); |
| finish(); |
| return; |
| } |
| |
| mForceCreate = true; |
| } |
| |
| // Launch a loader to look up the owner name. It should be ready well in advance of |
| // the time the user clicks next or manual. |
| getLoaderManager().initLoader(OWNER_NAME_LOADER_ID, null, new OwnerNameLoaderCallbacks()); |
| |
| // Launch a loader to cache some info about existing accounts so we can dupe-check against |
| // them. |
| getLoaderManager().initLoader(EXISTING_ACCOUNTS_LOADER_ID, null, |
| new ExistingAccountsLoaderCallbacks()); |
| } |
| |
| private class OwnerNameLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> { |
| @Override |
| public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { |
| return new CursorLoader(AccountSetupFinal.this, |
| ContactsContract.Profile.CONTENT_URI, |
| new String[] {ContactsContract.Profile.DISPLAY_NAME_PRIMARY}, |
| null, null, null); |
| } |
| |
| @Override |
| public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) { |
| if (data != null && data.moveToFirst()) { |
| mOwnerName = data.getString(data.getColumnIndex( |
| ContactsContract.Profile.DISPLAY_NAME_PRIMARY)); |
| } |
| } |
| |
| @Override |
| public void onLoaderReset(final Loader<Cursor> loader) {} |
| } |
| |
| private class ExistingAccountsLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> { |
| @Override |
| public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { |
| return new CursorLoader(AccountSetupFinal.this, MailAppProvider.getAccountsUri(), |
| new String[] {UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME, |
| UIProvider.AccountColumns.NAME}, |
| null, null, null); |
| } |
| |
| @Override |
| public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) { |
| if (data == null || !data.moveToFirst()) { |
| mExistingAccountsMap = null; |
| return; |
| } |
| |
| mExistingAccountsMap = new HashMap<>(); |
| |
| final int emailColumnIndex = data.getColumnIndex( |
| UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME); |
| final int displayNameColumnIndex = |
| data.getColumnIndex(UIProvider.AccountColumns.NAME); |
| |
| do { |
| final String email = data.getString(emailColumnIndex); |
| final String displayName = data.getString(displayNameColumnIndex); |
| mExistingAccountsMap.put(email, |
| TextUtils.isEmpty(displayName) ? email : displayName); |
| } while (data.moveToNext()); |
| } |
| |
| @Override |
| public void onLoaderReset(final Loader<Cursor> loader) { |
| mExistingAccountsMap = null; |
| } |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| |
| Analytics.getInstance().activityStart(this); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| if (mForceCreate) { |
| mForceCreate = false; |
| |
| // We need to do this after onCreate so that we can ensure that the fragment is |
| // fully created before querying it. |
| // This will call initiateAccountCreation() for us |
| proceed(); |
| } |
| } |
| |
| @Override |
| public void onSaveInstanceState(@NonNull Bundle outState) { |
| super.onSaveInstanceState(outState); |
| outState.putBoolean(SAVESTATE_KEY_IS_PROCESSING, mIsProcessing); |
| outState.putInt(SAVESTATE_KEY_STATE, mState); |
| outState.putSerializable(SAVESTATE_KEY_PROVIDER, mProvider); |
| outState.putParcelable(SAVESTATE_KEY_AUTHENTICATOR_RESPONSE, mAccountAuthenticatorResponse); |
| outState.putBoolean(SAVESTATE_KEY_REPORT_AUTHENTICATOR_ERROR, |
| mReportAccountAuthenticatorError); |
| outState.putBoolean(SAVESTATE_KEY_IS_PRE_CONFIGURED, mIsPreConfiguredProvider); |
| outState.putBoolean(SAVESTATE_KEY_PASSWORD_FAILED, mPasswordFailed); |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| |
| Analytics.getInstance().activityStop(this); |
| } |
| |
| /** |
| * Swap in the new fragment according to mState. This pushes the current fragment onto the back |
| * stack, so only call it once per transition. |
| */ |
| private void updateContentFragment(boolean addToBackstack) { |
| final AccountSetupFragment f; |
| String backstackTag = null; |
| |
| switch (mState) { |
| case STATE_BASICS: |
| f = AccountSetupBasicsFragment.newInstance(); |
| break; |
| case STATE_TYPE: |
| f = AccountSetupTypeFragment.newInstance(); |
| break; |
| case STATE_AB: |
| f = AccountSetupABFragment.newInstance(mSetupData.getEmail(), |
| mSetupData.getAmProtocol(), mSetupData.getIncomingProtocol(this)); |
| break; |
| case STATE_CREDENTIALS: |
| f = AccountSetupCredentialsFragment.newInstance(mSetupData.getEmail(), |
| mSetupData.getIncomingProtocol(this), mSetupData.getClientCert(this), |
| mPasswordFailed, false /* standalone */); |
| backstackTag = CREDENTIALS_BACKSTACK_TAG; |
| break; |
| case STATE_MANUAL_INCOMING: |
| f = AccountSetupIncomingFragment.newInstance(false); |
| break; |
| case STATE_MANUAL_OUTGOING: |
| f = AccountSetupOutgoingFragment.newInstance(false); |
| break; |
| case STATE_OPTIONS: |
| f = AccountSetupOptionsFragment.newInstance(); |
| break; |
| case STATE_NAMES: |
| f = AccountSetupNamesFragment.newInstance(); |
| break; |
| default: |
| throw new IllegalStateException("Incorrect state " + mState); |
| } |
| f.setState(mState); |
| final FragmentTransaction ft = getFragmentManager().beginTransaction(); |
| ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out); |
| ft.replace(R.id.setup_fragment_container, f, CONTENT_FRAGMENT_TAG); |
| if (addToBackstack) { |
| ft.addToBackStack(backstackTag); |
| } |
| ft.commit(); |
| |
| final InputMethodManager imm = |
| (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); |
| final View fragment_container = findViewById(R.id.setup_fragment_container); |
| imm.hideSoftInputFromWindow(fragment_container.getWindowToken(), |
| 0 /* flags: always hide */); |
| } |
| |
| /** |
| * Retrieve the current content fragment |
| * @return The content fragment or null if it wasn't found for some reason |
| */ |
| private AccountSetupFragment getContentFragment() { |
| return (AccountSetupFragment) getFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG); |
| } |
| |
| /** |
| * Reads the flow state saved into the current fragment and restores mState to it, also |
| * resetting the headline at the same time. |
| */ |
| private void resetStateFromCurrentFragment() { |
| AccountSetupFragment f = getContentFragment(); |
| mState = f.getState(); |
| } |
| |
| /** |
| * Main choreography function to handle moving forward through scenes. Moving back should be |
| * generally handled for us by the back stack |
| */ |
| protected void proceed() { |
| mIsProcessing = false; |
| final AccountSetupFragment oldContentFragment = getContentFragment(); |
| if (oldContentFragment != null) { |
| oldContentFragment.setNextButtonEnabled(true); |
| } |
| |
| getFragmentManager().executePendingTransactions(); |
| |
| switch (mState) { |
| case STATE_BASICS: |
| final boolean advance = onBasicsComplete(); |
| if (!advance) { |
| mState = STATE_BASICS_POST; |
| break; |
| } // else fall through |
| case STATE_BASICS_POST: |
| if (shouldDivertToManual()) { |
| mSkipAutoDiscover = true; |
| mIsPreConfiguredProvider = false; |
| mState = STATE_TYPE; |
| } else { |
| mSkipAutoDiscover = false; |
| if (mIsPreConfiguredProvider) { |
| if (!TextUtils.isEmpty(mSetupData.getAmProtocol()) && |
| !TextUtils.equals(mSetupData.getAmProtocol(), |
| mSetupData.getIncomingProtocol(this))) { |
| mState = STATE_AB; |
| } else { |
| mState = STATE_CREDENTIALS; |
| if (possiblyDivertToGmail()) { |
| return; |
| } |
| } |
| } else { |
| final String amProtocol = mSetupData.getAmProtocol(); |
| if (!TextUtils.isEmpty(amProtocol)) { |
| mSetupData.setIncomingProtocol(this, amProtocol); |
| final Account account = mSetupData.getAccount(); |
| setDefaultsForProtocol(account); |
| mState = STATE_CREDENTIALS; |
| } else { |
| mState = STATE_TYPE; |
| } |
| } |
| } |
| updateContentFragment(true /* addToBackstack */); |
| break; |
| case STATE_TYPE: |
| // We either got here through "Manual Setup" or because we didn't find the provider |
| mState = STATE_CREDENTIALS; |
| updateContentFragment(true /* addToBackstack */); |
| break; |
| case STATE_AB: |
| if (possiblyDivertToGmail()) { |
| return; |
| } |
| mState = STATE_CREDENTIALS; |
| updateContentFragment(true /* addToBackstack */); |
| break; |
| case STATE_CREDENTIALS: |
| collectCredentials(); |
| if (mIsPreConfiguredProvider) { |
| mState = STATE_CHECKING_PRECONFIGURED; |
| initiateCheckSettingsFragment(SetupDataFragment.CHECK_INCOMING |
| | SetupDataFragment.CHECK_OUTGOING); |
| } else { |
| populateHostAuthsFromSetupData(); |
| if (mSkipAutoDiscover) { |
| mState = STATE_MANUAL_INCOMING; |
| updateContentFragment(true /* addToBackstack */); |
| } else { |
| mState = STATE_AUTO_DISCOVER; |
| initiateAutoDiscover(); |
| } |
| } |
| break; |
| case STATE_CHECKING_PRECONFIGURED: |
| if (mPreConfiguredFailed) { |
| if (mPasswordFailed) { |
| // Get rid of the previous instance of the AccountSetupCredentialsFragment. |
| FragmentManager fm = getFragmentManager(); |
| fm.popBackStackImmediate(CREDENTIALS_BACKSTACK_TAG, 0); |
| final AccountSetupCredentialsFragment f = (AccountSetupCredentialsFragment) |
| getContentFragment(); |
| f.setPasswordFailed(mPasswordFailed); |
| resetStateFromCurrentFragment(); |
| } else { |
| mState = STATE_MANUAL_INCOMING; |
| updateContentFragment(true /* addToBackstack */); |
| } |
| } else { |
| mState = STATE_OPTIONS; |
| updateContentFragment(true /* addToBackstack */); |
| } |
| break; |
| case STATE_AUTO_DISCOVER: |
| // TODO: figure out if we can skip past manual setup |
| mState = STATE_MANUAL_INCOMING; |
| updateContentFragment(true); |
| break; |
| case STATE_MANUAL_INCOMING: |
| onIncomingComplete(); |
| mState = STATE_CHECKING_INCOMING; |
| initiateCheckSettingsFragment(SetupDataFragment.CHECK_INCOMING); |
| break; |
| case STATE_CHECKING_INCOMING: |
| final EmailServiceUtils.EmailServiceInfo serviceInfo = |
| mSetupData.getIncomingServiceInfo(this); |
| if (serviceInfo.usesSmtp) { |
| mState = STATE_MANUAL_OUTGOING; |
| } else { |
| mState = STATE_OPTIONS; |
| } |
| updateContentFragment(true /* addToBackstack */); |
| break; |
| case STATE_MANUAL_OUTGOING: |
| onOutgoingComplete(); |
| mState = STATE_CHECKING_OUTGOING; |
| initiateCheckSettingsFragment(SetupDataFragment.CHECK_OUTGOING); |
| break; |
| case STATE_CHECKING_OUTGOING: |
| mState = STATE_OPTIONS; |
| updateContentFragment(true /* addToBackstack */); |
| break; |
| case STATE_OPTIONS: |
| mState = STATE_CREATING; |
| initiateAccountCreation(); |
| break; |
| case STATE_CREATING: |
| mState = STATE_NAMES; |
| updateContentFragment(true /* addToBackstack */); |
| if (mSetupData.getFlowMode() == |
| AuthenticatorSetupIntentHelper.FLOW_MODE_FORCE_CREATE) { |
| getFragmentManager().executePendingTransactions(); |
| initiateAccountFinalize(); |
| } |
| break; |
| case STATE_NAMES: |
| initiateAccountFinalize(); |
| break; |
| case STATE_FINALIZE: |
| finish(); |
| break; |
| default: |
| LogUtils.wtf(LogUtils.TAG, "Unknown state %d", mState); |
| break; |
| } |
| } |
| |
| /** |
| * Check if we should divert to creating a Gmail account instead |
| * @return true if we diverted |
| */ |
| private boolean possiblyDivertToGmail() { |
| // TODO: actually divert here |
| final EmailServiceUtils.EmailServiceInfo info = |
| mSetupData.getIncomingServiceInfo(this); |
| if (TextUtils.equals(info.protocol, "gmail")) { |
| final Bundle options = new Bundle(1); |
| options.putBoolean("allowSkip", false); |
| AccountManager.get(this).addAccount("com.google", |
| "mail" /* authTokenType */, |
| null, |
| options, |
| this, null, null); |
| |
| finish(); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Block the back key if we are currently processing the "next" key" |
| */ |
| @Override |
| public void onBackPressed() { |
| if (mIsProcessing) { |
| return; |
| } |
| if (mState == STATE_NAMES) { |
| finish(); |
| } else { |
| super.onBackPressed(); |
| } |
| // After super.onBackPressed() our fragment should be in place, so query the state we |
| // installed it for |
| resetStateFromCurrentFragment(); |
| } |
| |
| @Override |
| public void setAccount(Account account) { |
| mSetupData.setAccount(account); |
| } |
| |
| @Override |
| public void finish() { |
| // If the account manager initiated the creation, and success was not reported, |
| // then we assume that we're giving up (for any reason) - report failure. |
| if (mReportAccountAuthenticatorError) { |
| if (mAccountAuthenticatorResponse != null) { |
| mAccountAuthenticatorResponse |
| .onError(AccountManager.ERROR_CODE_CANCELED, "canceled"); |
| mAccountAuthenticatorResponse = null; |
| } |
| } |
| super.finish(); |
| } |
| |
| @Override |
| public void onNextButton() { |
| // Some states are handled without UI, block double-presses here |
| if (!mIsProcessing) { |
| proceed(); |
| } |
| } |
| |
| /** |
| * @return true to proceed, false to remain on the current screen |
| */ |
| private boolean onBasicsComplete() { |
| final AccountSetupBasicsFragment f = (AccountSetupBasicsFragment) getContentFragment(); |
| final String email = f.getEmail(); |
| |
| // Reset the protocol choice in case the user has back-navigated here |
| mSetupData.setIncomingProtocol(this, null); |
| |
| if (!TextUtils.equals(email, mSetupData.getEmail())) { |
| // If the user changes their email address, clear the password failed state |
| mPasswordFailed = false; |
| } |
| mSetupData.setEmail(email); |
| |
| final String[] emailParts = email.split("@"); |
| final String domain = emailParts[1].trim(); |
| mProvider = AccountSettingsUtils.findProviderForDomain(this, domain); |
| if (mProvider != null) { |
| mIsPreConfiguredProvider = true; |
| if (mProvider.note != null) { |
| final AccountSetupNoteDialogFragment dialogFragment = |
| AccountSetupNoteDialogFragment.newInstance(mProvider.note); |
| dialogFragment.show(getFragmentManager(), AccountSetupNoteDialogFragment.TAG); |
| return false; |
| } else { |
| return finishAutoSetup(); |
| } |
| } else { |
| mIsPreConfiguredProvider = false; |
| final String existingAccountName = |
| mExistingAccountsMap != null ? mExistingAccountsMap.get(email) : null; |
| if (!TextUtils.isEmpty(existingAccountName)) { |
| showDuplicateAccountDialog(existingAccountName); |
| return false; |
| } else { |
| populateSetupData(mOwnerName, email); |
| mSkipAutoDiscover = false; |
| return true; |
| } |
| } |
| } |
| |
| private void showDuplicateAccountDialog(final String existingAccountName) { |
| final DuplicateAccountDialogFragment dialogFragment = |
| DuplicateAccountDialogFragment.newInstance(existingAccountName); |
| dialogFragment.show(getFragmentManager(), DuplicateAccountDialogFragment.TAG); |
| } |
| |
| @Override |
| public void onDuplicateAccountDialogDismiss() { |
| resetStateFromCurrentFragment(); |
| } |
| |
| private boolean shouldDivertToManual() { |
| final AccountSetupBasicsFragment f = (AccountSetupBasicsFragment) getContentFragment(); |
| return f.isManualSetup(); |
| } |
| |
| @Override |
| public void onCredentialsComplete(Bundle results) { |
| proceed(); |
| } |
| |
| private void collectCredentials() { |
| final AccountSetupCredentialsFragment f = (AccountSetupCredentialsFragment) |
| getContentFragment(); |
| final Bundle results = f.getCredentialResults(); |
| mSetupData.setCredentialResults(results); |
| final Account account = mSetupData.getAccount(); |
| final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); |
| AccountSetupCredentialsFragment.populateHostAuthWithResults(this, recvAuth, |
| mSetupData.getCredentialResults()); |
| mSetupData.setIncomingCredLoaded(true); |
| final EmailServiceUtils.EmailServiceInfo info = mSetupData.getIncomingServiceInfo(this); |
| if (info.usesSmtp) { |
| final HostAuth sendAuth = account.getOrCreateHostAuthSend(this); |
| AccountSetupCredentialsFragment.populateHostAuthWithResults(this, sendAuth, |
| mSetupData.getCredentialResults()); |
| mSetupData.setOutgoingCredLoaded(true); |
| } |
| } |
| |
| @Override |
| public void onNoteDialogComplete() { |
| finishAutoSetup(); |
| proceed(); |
| } |
| |
| @Override |
| public void onNoteDialogCancel() { |
| resetStateFromCurrentFragment(); |
| } |
| |
| /** |
| * Finish the auto setup process, in some cases after showing a warning dialog. |
| * Happens after onBasicsComplete |
| * @return true to proceed, false to remain on the current screen |
| */ |
| private boolean finishAutoSetup() { |
| final String email = mSetupData.getEmail(); |
| |
| try { |
| mProvider.expandTemplates(email); |
| |
| final String primaryProtocol = HostAuth.getProtocolFromString(mProvider.incomingUri); |
| EmailServiceUtils.EmailServiceInfo info = |
| EmailServiceUtils.getServiceInfo(this, primaryProtocol); |
| // If the protocol isn't one we can use, and we're not diverting to gmail, try the alt |
| if (!info.isGmailStub && !EmailServiceUtils.isServiceAvailable(this, info.protocol)) { |
| LogUtils.d(LogUtils.TAG, "Protocol %s not available, using alternate", |
| info.protocol); |
| mProvider.expandAlternateTemplates(email); |
| final String alternateProtocol = HostAuth.getProtocolFromString( |
| mProvider.incomingUri); |
| info = EmailServiceUtils.getServiceInfo(this, alternateProtocol); |
| } |
| final Account account = mSetupData.getAccount(); |
| final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); |
| recvAuth.setHostAuthFromString(mProvider.incomingUri); |
| |
| recvAuth.setUserName(mProvider.incomingUsername); |
| recvAuth.mPort = |
| ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) ? info.portSsl : info.port; |
| |
| if (info.usesSmtp) { |
| final HostAuth sendAuth = account.getOrCreateHostAuthSend(this); |
| sendAuth.setHostAuthFromString(mProvider.outgoingUri); |
| sendAuth.setUserName(mProvider.outgoingUsername); |
| } |
| |
| // Populate the setup data, assuming that the duplicate account check will succeed |
| populateSetupData(mOwnerName, email); |
| |
| final String duplicateAccountName = |
| mExistingAccountsMap != null ? mExistingAccountsMap.get(email) : null; |
| if (duplicateAccountName != null) { |
| showDuplicateAccountDialog(duplicateAccountName); |
| return false; |
| } |
| } catch (URISyntaxException e) { |
| mSkipAutoDiscover = false; |
| mPreConfiguredFailed = true; |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Helper method to fill in some per-protocol defaults |
| * @param account Account object to fill in |
| */ |
| public void setDefaultsForProtocol(Account account) { |
| final EmailServiceUtils.EmailServiceInfo info = mSetupData.getIncomingServiceInfo(this); |
| if (info == null) return; |
| account.mSyncInterval = info.defaultSyncInterval; |
| account.mSyncLookback = info.defaultLookback; |
| if (info.offerLocalDeletes) { |
| account.setDeletePolicy(info.defaultLocalDeletes); |
| } |
| } |
| |
| /** |
| * Populate SetupData's account with complete setup info, assumes that the receive auth is |
| * created and its protocol is set |
| */ |
| private void populateSetupData(String senderName, String senderEmail) { |
| final Account account = mSetupData.getAccount(); |
| account.setSenderName(senderName); |
| account.setEmailAddress(senderEmail); |
| account.setDisplayName(senderEmail); |
| setDefaultsForProtocol(account); |
| } |
| |
| private void onIncomingComplete() { |
| AccountSetupIncomingFragment f = (AccountSetupIncomingFragment) getContentFragment(); |
| f.collectUserInput(); |
| } |
| |
| private void onOutgoingComplete() { |
| AccountSetupOutgoingFragment f = (AccountSetupOutgoingFragment) getContentFragment(); |
| f.collectUserInput(); |
| } |
| |
| // This callback method is only applicable to using Incoming/Outgoing fragments in settings mode |
| @Override |
| public void onAccountServerUIComplete(int checkMode) {} |
| |
| // This callback method is only applicable to using Incoming/Outgoing fragments in settings mode |
| @Override |
| public void onAccountServerSaveComplete() {} |
| |
| private void populateHostAuthsFromSetupData() { |
| final String email = mSetupData.getEmail(); |
| final String[] emailParts = email.split("@"); |
| final String domain = emailParts[1]; |
| |
| final Account account = mSetupData.getAccount(); |
| final EmailServiceUtils.EmailServiceInfo info = |
| mSetupData.getIncomingServiceInfo(this); |
| |
| final HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); |
| recvAuth.setUserName(email); |
| recvAuth.setConnection(mSetupData.getIncomingProtocol(), domain, |
| HostAuth.PORT_UNKNOWN, info.offerTls ? HostAuth.FLAG_TLS : HostAuth.FLAG_SSL); |
| AccountSetupCredentialsFragment.populateHostAuthWithResults(this, recvAuth, |
| mSetupData.getCredentialResults()); |
| mSetupData.setIncomingCredLoaded(true); |
| |
| if (info.usesSmtp) { |
| final HostAuth sendAuth = account.getOrCreateHostAuthSend(this); |
| sendAuth.setUserName(email); |
| sendAuth.setConnection(HostAuth.LEGACY_SCHEME_SMTP, domain, |
| HostAuth.PORT_UNKNOWN, HostAuth.FLAG_TLS); |
| AccountSetupCredentialsFragment.populateHostAuthWithResults(this, sendAuth, |
| mSetupData.getCredentialResults()); |
| mSetupData.setOutgoingCredLoaded(true); |
| } |
| } |
| |
| private void initiateAutoDiscover() { |
| // Populate the setup data, assuming that the duplicate account check will succeed |
| initiateCheckSettingsFragment(SetupDataFragment.CHECK_AUTODISCOVER); |
| } |
| |
| private void initiateCheckSettingsFragment(int checkMode) { |
| final Fragment f = AccountCheckSettingsFragment.newInstance(checkMode); |
| final Fragment d = CheckSettingsProgressDialogFragment.newInstance(checkMode); |
| getFragmentManager().beginTransaction() |
| .add(f, AccountCheckSettingsFragment.TAG) |
| .add(d, CheckSettingsProgressDialogFragment.TAG) |
| .commit(); |
| } |
| |
| @Override |
| public void onCheckSettingsProgressDialogCancel() { |
| dismissCheckSettingsFragment(); |
| resetStateFromCurrentFragment(); |
| } |
| |
| private void dismissCheckSettingsFragment() { |
| final Fragment f = getFragmentManager().findFragmentByTag(AccountCheckSettingsFragment.TAG); |
| final Fragment d = |
| getFragmentManager().findFragmentByTag(CheckSettingsProgressDialogFragment.TAG); |
| getFragmentManager().beginTransaction() |
| .remove(f) |
| .remove(d) |
| .commit(); |
| } |
| |
| @Override |
| public void onCheckSettingsError(int reason, String message) { |
| if (reason == CheckSettingsErrorDialogFragment.REASON_AUTHENTICATION_FAILED || |
| reason == CheckSettingsErrorDialogFragment.REASON_CERTIFICATE_REQUIRED) { |
| // TODO: possibly split password and cert error conditions |
| mPasswordFailed = true; |
| } |
| dismissCheckSettingsFragment(); |
| final DialogFragment f = |
| CheckSettingsErrorDialogFragment.newInstance(reason, message); |
| f.show(getFragmentManager(), CheckSettingsErrorDialogFragment.TAG); |
| } |
| |
| @Override |
| public void onCheckSettingsErrorDialogEditCertificate() { |
| if (mState == STATE_CHECKING_PRECONFIGURED) { |
| mPreConfiguredFailed = true; |
| proceed(); |
| } else { |
| resetStateFromCurrentFragment(); |
| } |
| final AccountSetupIncomingFragment f = (AccountSetupIncomingFragment) getContentFragment(); |
| f.onCertificateRequested(); |
| } |
| |
| @Override |
| public void onCheckSettingsErrorDialogEditSettings() { |
| // If we're checking pre-configured, set a flag that we failed and navigate forwards to |
| // incoming settings |
| if (mState == STATE_CHECKING_PRECONFIGURED || mState == STATE_AUTO_DISCOVER) { |
| mPreConfiguredFailed = true; |
| proceed(); |
| } else { |
| resetStateFromCurrentFragment(); |
| } |
| } |
| |
| @Override |
| public void onCheckSettingsComplete() { |
| mPreConfiguredFailed = false; |
| mPasswordFailed = false; |
| dismissCheckSettingsFragment(); |
| proceed(); |
| } |
| |
| @Override |
| public void onCheckSettingsAutoDiscoverComplete(int result) { |
| dismissCheckSettingsFragment(); |
| proceed(); |
| } |
| |
| @Override |
| public void onCheckSettingsSecurityRequired(String hostName) { |
| dismissCheckSettingsFragment(); |
| final DialogFragment f = SecurityRequiredDialogFragment.newInstance(hostName); |
| f.show(getFragmentManager(), SecurityRequiredDialogFragment.TAG); |
| } |
| |
| @Override |
| public void onSecurityRequiredDialogResult(boolean ok) { |
| if (ok) { |
| proceed(); |
| } else { |
| resetStateFromCurrentFragment(); |
| } |
| } |
| |
| @Override |
| public void onChooseProtocol(String protocol) { |
| mSetupData.setIncomingProtocol(this, protocol); |
| final Account account = mSetupData.getAccount(); |
| setDefaultsForProtocol(account); |
| proceed(); |
| } |
| |
| @Override |
| public void onABProtocolDisambiguated(String chosenProtocol) { |
| if (!TextUtils.equals(mSetupData.getIncomingProtocol(this), chosenProtocol)) { |
| mIsPreConfiguredProvider = false; |
| mSetupData.setIncomingProtocol(this, chosenProtocol); |
| final Account account = mSetupData.getAccount(); |
| setDefaultsForProtocol(account); |
| } |
| proceed(); |
| } |
| |
| /** |
| * Ths is called when the user clicks the "done" button. |
| * It collects the data from the UI, updates the setup account record, and launches a fragment |
| * which handles creating the account in the system and database. |
| */ |
| private void initiateAccountCreation() { |
| mIsProcessing = true; |
| getContentFragment().setNextButtonEnabled(false); |
| |
| final Account account = mSetupData.getAccount(); |
| if (account.mHostAuthRecv == null) { |
| throw new IllegalStateException("in AccountSetupOptions with null mHostAuthRecv"); |
| } |
| |
| final AccountSetupOptionsFragment fragment = (AccountSetupOptionsFragment) |
| getContentFragment(); |
| if (fragment == null) { |
| throw new IllegalStateException("Fragment missing!"); |
| } |
| |
| account.setDisplayName(account.getEmailAddress()); |
| int newFlags = account.getFlags() & ~(Account.FLAGS_BACKGROUND_ATTACHMENTS); |
| final EmailServiceUtils.EmailServiceInfo serviceInfo = |
| mSetupData.getIncomingServiceInfo(this); |
| if (serviceInfo.offerAttachmentPreload && fragment.getBackgroundAttachmentsValue()) { |
| newFlags |= Account.FLAGS_BACKGROUND_ATTACHMENTS; |
| } |
| final HostAuth hostAuth = account.getOrCreateHostAuthRecv(this); |
| if (hostAuth.mProtocol.equals(getString(R.string.protocol_eas))) { |
| try { |
| final double protocolVersionDouble = Double.parseDouble(account.mProtocolVersion); |
| if (protocolVersionDouble >= 12.0) { |
| // If the the account is EAS and the protocol version is above 12.0, |
| // we know that SmartForward is enabled and the various search flags |
| // should be enabled first. |
| // TODO: Move this into protocol specific code in the future. |
| newFlags |= Account.FLAGS_SUPPORTS_SMART_FORWARD | |
| Account.FLAGS_SUPPORTS_GLOBAL_SEARCH | Account.FLAGS_SUPPORTS_SEARCH; |
| } |
| } catch (NumberFormatException e) { |
| LogUtils.wtf(LogUtils.TAG, e, "Exception thrown parsing the protocol version."); |
| } |
| } |
| account.setFlags(newFlags); |
| account.setSyncInterval(fragment.getCheckFrequencyValue()); |
| final Integer syncWindowValue = fragment.getAccountSyncWindowValue(); |
| if (syncWindowValue != null) { |
| account.setSyncLookback(syncWindowValue); |
| } |
| |
| // Finish setting up the account, and commit it to the database |
| if (mSetupData.getPolicy() != null) { |
| account.mFlags |= Account.FLAGS_SECURITY_HOLD; |
| account.mPolicy = mSetupData.getPolicy(); |
| } |
| |
| // Finally, write the completed account (for the first time) and then |
| // install it into the Account manager as well. These are done off-thread. |
| // The account manager will report back via the callback, which will take us to |
| // the next operations. |
| final boolean syncEmail = fragment.getSyncEmailValue(); |
| final boolean syncCalendar = serviceInfo.syncCalendar && fragment.getSyncCalendarValue(); |
| final boolean syncContacts = serviceInfo.syncContacts && fragment.getSyncContactsValue(); |
| final boolean enableNotifications = fragment.getNotifyValue(); |
| |
| final Fragment f = AccountCreationFragment.newInstance(account, syncEmail, syncCalendar, |
| syncContacts, enableNotifications); |
| final FragmentTransaction ft = getFragmentManager().beginTransaction(); |
| ft.add(f, AccountCreationFragment.TAG); |
| ft.commit(); |
| |
| showCreateAccountDialog(); |
| } |
| |
| /** |
| * Called by the account creation fragment after it has completed. |
| * We do a small amount of work here before moving on to the next state. |
| */ |
| @Override |
| public void onAccountCreationFragmentComplete() { |
| destroyAccountCreationFragment(); |
| // If the account manager initiated the creation, and success was not reported, |
| // then we assume that we're giving up (for any reason) - report failure. |
| if (mAccountAuthenticatorResponse != null) { |
| final EmailServiceUtils.EmailServiceInfo info = mSetupData.getIncomingServiceInfo(this); |
| final Bundle b = new Bundle(2); |
| b.putString(AccountManager.KEY_ACCOUNT_NAME, mSetupData.getEmail()); |
| b.putString(AccountManager.KEY_ACCOUNT_TYPE, info.accountType); |
| mAccountAuthenticatorResponse.onResult(b); |
| mAccountAuthenticatorResponse = null; |
| mReportAccountAuthenticatorError = false; |
| } |
| setResult(RESULT_OK); |
| proceed(); |
| } |
| |
| @Override |
| public void destroyAccountCreationFragment() { |
| dismissCreateAccountDialog(); |
| |
| final Fragment f = getFragmentManager().findFragmentByTag(AccountCreationFragment.TAG); |
| if (f == null) { |
| LogUtils.wtf(LogUtils.TAG, "Couldn't find AccountCreationFragment to destroy"); |
| } |
| getFragmentManager().beginTransaction() |
| .remove(f) |
| .commit(); |
| } |
| |
| |
| public static class CreateAccountDialogFragment extends DialogFragment { |
| public static final String TAG = "CreateAccountDialogFragment"; |
| public CreateAccountDialogFragment() {} |
| |
| public static CreateAccountDialogFragment newInstance() { |
| return new CreateAccountDialogFragment(); |
| } |
| |
| @Override |
| public Dialog onCreateDialog(Bundle savedInstanceState) { |
| /// Show "Creating account..." dialog |
| setCancelable(false); |
| final ProgressDialog d = new ProgressDialog(getActivity()); |
| d.setIndeterminate(true); |
| d.setMessage(getString(R.string.account_setup_creating_account_msg)); |
| return d; |
| } |
| } |
| |
| protected void showCreateAccountDialog() { |
| CreateAccountDialogFragment.newInstance() |
| .show(getFragmentManager(), CreateAccountDialogFragment.TAG); |
| } |
| |
| protected void dismissCreateAccountDialog() { |
| final DialogFragment f = (DialogFragment) |
| getFragmentManager().findFragmentByTag(CreateAccountDialogFragment.TAG); |
| if (f != null) { |
| f.dismiss(); |
| } |
| } |
| |
| public static class CreateAccountErrorDialogFragment extends DialogFragment |
| implements DialogInterface.OnClickListener { |
| public CreateAccountErrorDialogFragment() {} |
| |
| @Override |
| public Dialog onCreateDialog(Bundle savedInstanceState) { |
| final String message = getString(R.string.account_setup_failed_dlg_auth_message, |
| R.string.system_account_create_failed); |
| |
| setCancelable(false); |
| return new AlertDialog.Builder(getActivity()) |
| .setIconAttribute(android.R.attr.alertDialogIcon) |
| .setTitle(R.string.account_setup_failed_dlg_title) |
| .setMessage(message) |
| .setPositiveButton(android.R.string.ok, this) |
| .create(); |
| } |
| |
| @Override |
| public void onClick(DialogInterface dialog, int which) { |
| getActivity().finish(); |
| } |
| } |
| |
| /** |
| * This is called if MailService.setupAccountManagerAccount() fails for some reason |
| */ |
| @Override |
| public void showCreateAccountErrorDialog() { |
| new CreateAccountErrorDialogFragment().show(getFragmentManager(), null); |
| } |
| |
| /** |
| * Collect the data from AccountSetupNames and finish up account creation |
| */ |
| private void initiateAccountFinalize() { |
| mIsProcessing = true; |
| getContentFragment().setNextButtonEnabled(false); |
| |
| AccountSetupNamesFragment fragment = (AccountSetupNamesFragment) getContentFragment(); |
| // Update account object from UI |
| final Account account = mSetupData.getAccount(); |
| final String description = fragment.getDescription(); |
| if (!TextUtils.isEmpty(description)) { |
| account.setDisplayName(description); |
| } |
| account.setSenderName(fragment.getSenderName()); |
| |
| final Fragment f = AccountFinalizeFragment.newInstance(account); |
| final FragmentTransaction ft = getFragmentManager().beginTransaction(); |
| ft.add(f, AccountFinalizeFragment.TAG); |
| ft.commit(); |
| } |
| |
| /** |
| * Called when the AccountFinalizeFragment has finished its tasks |
| */ |
| @Override |
| public void onAccountFinalizeFragmentComplete() { |
| finish(); |
| } |
| } |