AccountSetupBasics.java revision a97faa25ac3265209b50d4534b4c2b41cd211e5c
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.activity.setup;
18
19import com.android.email.Email;
20import com.android.email.EmailAddressValidator;
21import com.android.email.R;
22import com.android.email.Utility;
23import com.android.email.VendorPolicyLoader;
24import com.android.email.activity.ActivityHelper;
25import com.android.email.activity.Welcome;
26import com.android.email.activity.setup.AccountSettingsUtils.Provider;
27import com.android.email.provider.EmailContent;
28import com.android.email.provider.EmailContent.Account;
29import com.android.email.provider.EmailContent.HostAuth;
30
31import android.accounts.AccountAuthenticatorResponse;
32import android.accounts.AccountManager;
33import android.app.Activity;
34import android.app.ActivityManager;
35import android.app.AlertDialog;
36import android.app.Dialog;
37import android.app.DialogFragment;
38import android.app.FragmentTransaction;
39import android.content.Context;
40import android.content.DialogInterface;
41import android.content.Intent;
42import android.os.AsyncTask;
43import android.os.Bundle;
44import android.text.Editable;
45import android.text.TextUtils;
46import android.text.TextWatcher;
47import android.util.Log;
48import android.view.View;
49import android.view.View.OnClickListener;
50import android.widget.Button;
51import android.widget.CheckBox;
52import android.widget.EditText;
53import android.widget.TextView;
54import android.widget.Toast;
55
56import java.net.URI;
57import java.net.URISyntaxException;
58import java.util.concurrent.Callable;
59import java.util.concurrent.ExecutionException;
60import java.util.concurrent.FutureTask;
61
62/**
63 * Prompts the user for the email address and password. Also prompts for "Use this account as
64 * default" if this is the 2nd+ account being set up.
65 *
66 * If the domain is well-known, the account is configured fully and checked immediately
67 * using AccountCheckSettingsFragment.  If this succeeds we proceed directly to AccountSetupOptions.
68 *
69 * If the domain is not known, or the user selects Manual setup, we invoke the
70 * AccountSetupAccountType activity where the user can begin to manually configure the account.
71 *
72 * === Support for automated testing ==
73 * This activity can also be launched directly via ACTION_CREATE_ACCOUNT.  This is intended
74 * only for use by continuous test systems, and is currently only available when
75 * {@link ActivityManager#isRunningInTestHarness()} is set.  To use this mode, you must construct
76 * an intent which contains all necessary information to create the account.  No connection
77 * checking is done, so the account may or may not actually work.  Here is a sample command, for a
78 * gmail account "test_account" with a password of "test_password".
79 *
80 *      $ adb shell am start -a com.android.email.CREATE_ACCOUNT \
81 *          -e EMAIL test_account@gmail.com \
82 *          -e USER "Test Account Name" \
83 *          -e INCOMING imap+ssl+://test_account:test_password@imap.gmail.com \
84 *          -e OUTGOING smtp+ssl+://test_account:test_password@smtp.gmail.com
85 *
86 * Note: For accounts that require the full email address in the login, encode the @ as %40.
87 * Note: Exchange accounts that require device security policies cannot be created automatically.
88 */
89public class AccountSetupBasics extends AccountSetupActivity
90        implements OnClickListener, TextWatcher, AccountCheckSettingsFragment.Callbacks {
91
92    private final static boolean ENTER_DEBUG_SCREEN = true;
93
94    /**
95     * Direct access for forcing account creation
96     * For use by continuous automated test system (e.g. in conjunction with monkey tests)
97     */
98    private final String ACTION_CREATE_ACCOUNT = "com.android.email.CREATE_ACCOUNT";
99    private final String EXTRA_CREATE_ACCOUNT_EMAIL = "EMAIL";
100    private final String EXTRA_CREATE_ACCOUNT_USER = "USER";
101    private final String EXTRA_CREATE_ACCOUNT_INCOMING = "INCOMING";
102    private final String EXTRA_CREATE_ACCOUNT_OUTGOING = "OUTGOING";
103    private final Boolean DEBUG_ALLOW_NON_TEST_HARNESS_CREATION = false;
104
105    private final static String STATE_KEY_PROVIDER = "AccountSetupBasics.provider";
106
107    // NOTE: If you change this value, confirm that the new interval exists in arrays.xml
108    private final static int DEFAULT_ACCOUNT_CHECK_INTERVAL = 15;
109
110    // Support for UI
111    private TextView mWelcomeView;
112    private EditText mEmailView;
113    private EditText mPasswordView;
114    private CheckBox mDefaultView;
115    private EmailAddressValidator mEmailValidator = new EmailAddressValidator();
116    private Provider mProvider;
117    private Button mManualButton;
118    private Button mNextButton;
119    private boolean mNextButtonInhibit;
120    private boolean mPaused;
121
122    // Used when this Activity is called as part of account authentification flow,
123    // which requires to do extra work before and after the account creation.
124    // See also AccountAuthenticatorActivity.
125    private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
126    private Bundle mResultBundle = null;
127
128    // FutureTask to look up the owner
129    FutureTask<String> mOwnerLookupTask;
130
131    public static void actionNewAccount(Activity fromActivity) {
132        SetupData.init(SetupData.FLOW_MODE_NORMAL);
133        fromActivity.startActivity(new Intent(fromActivity, AccountSetupBasics.class));
134    }
135
136    /**
137     * This generates setup data that can be used to start a self-contained account creation flow
138     * for exchange accounts.
139     */
140    public static Intent actionSetupExchangeIntent(Context context) {
141        SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS);
142        return new Intent(context, AccountSetupBasics.class);
143    }
144
145    /**
146     * This generates setup data that can be used to start a self-contained account creation flow
147     * for pop/imap accounts.
148     */
149    public static Intent actionSetupPopImapIntent(Context context) {
150        SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP);
151        return new Intent(context, AccountSetupBasics.class);
152    }
153
154    public static void actionAccountCreateFinishedAccountFlow(Activity fromActivity) {
155        Intent i= new Intent(fromActivity, AccountSetupBasics.class);
156        // If we're in the "account flow" (from AccountManager), we want to return to the caller
157        // (in the settings app)
158        SetupData.init(SetupData.FLOW_MODE_RETURN_TO_CALLER);
159        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
160        fromActivity.startActivity(i);
161    }
162
163    public static void actionAccountCreateFinished(final Activity fromActivity,
164            final long accountId) {
165        Utility.runAsync(new Runnable() {
166           public void run() {
167               Intent i = new Intent(fromActivity, AccountSetupBasics.class);
168               // If we're not in the "account flow" (from AccountManager), we want to show the
169               // message list for the new inbox
170               Account account = Account.restoreAccountWithId(fromActivity, accountId);
171               SetupData.init(SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST, account);
172               i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
173               fromActivity.startActivity(i);
174            }});
175    }
176
177    @Override
178    public void onCreate(Bundle savedInstanceState) {
179        super.onCreate(savedInstanceState);
180        ActivityHelper.debugSetWindowFlags(this);
181
182        // Check for forced account creation first, as it comes from an externally-generated
183        // intent and won't have any SetupData prepared.
184        String action = getIntent().getAction();
185        if (ACTION_CREATE_ACCOUNT.equals(action)) {
186            SetupData.init(SetupData.FLOW_MODE_FORCE_CREATE);
187        }
188
189        int flowMode = SetupData.getFlowMode();
190        if (flowMode == SetupData.FLOW_MODE_RETURN_TO_CALLER) {
191            // Return to the caller who initiated account creation
192            finish();
193            return;
194        } else if (flowMode == SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST) {
195            Account account = SetupData.getAccount();
196            if (account != null && account.mId >= 0) {
197                // Show the message list for the new account
198                Welcome.actionOpenAccountInbox(this, account.mId);
199                finish();
200                return;
201            }
202        }
203
204        setContentView(R.layout.account_setup_basics);
205
206        mWelcomeView = (TextView) findViewById(R.id.instructions);
207        mEmailView = (EditText) findViewById(R.id.account_email);
208        mPasswordView = (EditText) findViewById(R.id.account_password);
209        mDefaultView = (CheckBox) findViewById(R.id.account_default);
210
211        mEmailView.addTextChangedListener(this);
212        mPasswordView.addTextChangedListener(this);
213
214        // If there are one or more accounts already in existence, then display
215        // the "use as default" checkbox (it defaults to hidden).
216        new DisplayCheckboxTask().execute();
217
218        boolean manualButtonDisplayed = true;
219        boolean alternateStrings = false;
220        if (flowMode == SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) {
221            // No need for manual button -> next is appropriate
222            manualButtonDisplayed = false;
223            // Swap welcome text for EAS-specific text
224            alternateStrings = VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings();
225            setTitle(alternateStrings
226                    ? R.string.account_setup_basics_exchange_title_alternate
227                    : R.string.account_setup_basics_exchange_title);
228            mWelcomeView.setText(alternateStrings
229                    ? R.string.accounts_welcome_exchange_alternate
230                    : R.string.accounts_welcome_exchange);
231        }
232
233        // Configure buttons
234        mManualButton = (Button) findViewById(R.id.manual_setup);
235        mNextButton = (Button) findViewById(R.id.next);
236        mManualButton.setVisibility(manualButtonDisplayed ? View.VISIBLE : View.INVISIBLE);
237        mManualButton.setOnClickListener(this);
238        mNextButton.setOnClickListener(this);
239        // Force disabled until validator notifies otherwise
240        onEnableProceedButtons(false);
241        // Lightweight debounce while Async tasks underway
242        mNextButtonInhibit = false;
243
244        mAccountAuthenticatorResponse =
245            getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
246
247        if (mAccountAuthenticatorResponse != null) {
248            mAccountAuthenticatorResponse.onRequestContinued();
249        }
250
251        // Load fields, but only once
252        String userName = SetupData.getUsername();
253        if (userName != null) {
254            mEmailView.setText(userName);
255            SetupData.setUsername(null);
256        }
257        String password = SetupData.getPassword();
258        if (userName != null) {
259            mPasswordView.setText(password);
260            SetupData.setPassword(null);
261        }
262
263        // Handle force account creation immediately (now that fragment is set up)
264        // This is never allowed in a normal user build and will exit immediately.
265        if (SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) {
266            if (!DEBUG_ALLOW_NON_TEST_HARNESS_CREATION &&
267                    !ActivityManager.isRunningInTestHarness()) {
268                Log.e(Email.LOG_TAG,
269                        "ERROR: Force account create only allowed while in test harness");
270                finish();
271                return;
272            }
273            Intent intent = getIntent();
274            String email = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_EMAIL);
275            String user = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_USER);
276            String incoming = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_INCOMING);
277            String outgoing = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_OUTGOING);
278            if (TextUtils.isEmpty(email) || TextUtils.isEmpty(user) ||
279                    TextUtils.isEmpty(incoming) || TextUtils.isEmpty(outgoing)) {
280                Log.e(Email.LOG_TAG, "ERROR: Force account create requires extras EMAIL, USER, " +
281                        "INCOMING, OUTGOING");
282                finish();
283                return;
284            }
285            forceCreateAccount(email, user, incoming, outgoing);
286            onCheckSettingsComplete(AccountCheckSettingsFragment.CHECK_SETTINGS_OK); // calls finish
287            return;
288        }
289
290        if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) {
291            mProvider = (Provider) savedInstanceState.getSerializable(STATE_KEY_PROVIDER);
292        }
293
294        // Launch a worker to look up the owner name.  It should be ready well in advance of
295        // the time the user clicks next or manual.
296        mOwnerLookupTask = new FutureTask<String>(mOwnerLookupCallable);
297        Utility.runAsync(mOwnerLookupTask);
298    }
299
300    @Override
301    public void onPause() {
302        super.onPause();
303        mPaused = true;
304    }
305
306    @Override
307    public void onResume() {
308        super.onResume();
309        mPaused = false;
310    }
311
312    @Override
313    public void finish() {
314        if (mAccountAuthenticatorResponse != null) {
315            // send the result bundle back if set, otherwise send an error.
316            if (mResultBundle != null) {
317                mAccountAuthenticatorResponse.onResult(mResultBundle);
318            } else {
319                mAccountAuthenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED,
320                        "canceled");
321            }
322            mAccountAuthenticatorResponse = null;
323        }
324        super.finish();
325    }
326
327    @Override
328    public void onSaveInstanceState(Bundle outState) {
329        super.onSaveInstanceState(outState);
330        if (mProvider != null) {
331            outState.putSerializable(STATE_KEY_PROVIDER, mProvider);
332        }
333    }
334
335    /**
336     * Implements OnClickListener
337     */
338    @Override
339    public void onClick(View v) {
340        switch (v.getId()) {
341            case R.id.next:
342                // Simple debounce - just ignore while async checks are underway
343                if (mNextButtonInhibit) {
344                    return;
345                }
346                onNext();
347                break;
348            case R.id.manual_setup:
349                onManualSetup(false);
350                break;
351        }
352    }
353
354    /**
355     * Implements TextWatcher
356     */
357    public void afterTextChanged(Editable s) {
358        validateFields();
359    }
360
361    /**
362     * Implements TextWatcher
363     */
364    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
365    }
366
367    /**
368     * Implements TextWatcher
369     */
370    public void onTextChanged(CharSequence s, int start, int before, int count) {
371    }
372
373    private void validateFields() {
374        boolean valid = Utility.isTextViewNotEmpty(mEmailView)
375                && Utility.isTextViewNotEmpty(mPasswordView)
376                && mEmailValidator.isValid(mEmailView.getText().toString().trim());
377        onEnableProceedButtons(valid);
378
379        // Warn (but don't prevent) if password has leading/trailing spaces
380        AccountSettingsUtils.checkPasswordSpaces(this, mPasswordView);
381    }
382
383    /**
384     * Return an existing username if found, or null.  This is the result of the Callable (below).
385     */
386    private String getOwnerName() {
387        String result = null;
388        try {
389            result = mOwnerLookupTask.get();
390        } catch (InterruptedException e) {
391        } catch (ExecutionException e) {
392        }
393        return result;
394    }
395
396    /**
397     * Callable that returns the username (based on other accounts) or null.
398     */
399    private Callable<String> mOwnerLookupCallable = new Callable<String>() {
400        public String call() {
401            Context context = AccountSetupBasics.this;
402            String name = null;
403            long defaultId = Account.getDefaultAccountId(context);
404            if (defaultId != -1) {
405                Account account = Account.restoreAccountWithId(context, defaultId);
406                if (account != null) {
407                    name = account.getSenderName();
408                }
409            }
410            return name;
411        }
412    };
413
414    /**
415     * Finish the auto setup process, in some cases after showing a warning dialog.
416     */
417    private void finishAutoSetup() {
418        String email = mEmailView.getText().toString().trim();
419        String password = mPasswordView.getText().toString();
420        String[] emailParts = email.split("@");
421        String user = emailParts[0];
422        String domain = emailParts[1];
423        URI incomingUri = null;
424        URI outgoingUri = null;
425        String incomingUsername = mProvider.incomingUsernameTemplate;
426        try {
427            incomingUsername = incomingUsername.replaceAll("\\$email", email);
428            incomingUsername = incomingUsername.replaceAll("\\$user", user);
429            incomingUsername = incomingUsername.replaceAll("\\$domain", domain);
430
431            URI incomingUriTemplate = mProvider.incomingUriTemplate;
432            incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":"
433                    + password, incomingUriTemplate.getHost(), incomingUriTemplate.getPort(),
434                    incomingUriTemplate.getPath(), null, null);
435
436            String outgoingUsername = mProvider.outgoingUsernameTemplate;
437            outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
438            outgoingUsername = outgoingUsername.replaceAll("\\$user", user);
439            outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);
440
441            URI outgoingUriTemplate = mProvider.outgoingUriTemplate;
442            outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
443                    + password, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(),
444                    outgoingUriTemplate.getPath(), null, null);
445
446        } catch (URISyntaxException use) {
447            /*
448             * If there is some problem with the URI we give up and go on to
449             * manual setup.  Technically speaking, AutoDiscover is OK here, since user clicked
450             * "Next" to get here.  This would never happen in practice because we don't expect
451             * to find any EAS accounts in the providers list.
452             */
453            onManualSetup(true);
454            return;
455        }
456
457        // Populate the setup data, assuming that the duplicate account check will succeed
458        populateSetupData(getOwnerName(), email, mDefaultView.isChecked(),
459                incomingUri.toString(), outgoingUri.toString());
460
461        // Stop here if the login credentials duplicate an existing account
462        // Launch an Async task to do the work
463        new DuplicateCheckTask(this, incomingUri.getHost(), incomingUsername).execute();
464    }
465
466    /**
467     * Async task that continues the work of finishAutoSetup().  Checks for a duplicate
468     * account and then either alerts the user, or continues.
469     */
470    private class DuplicateCheckTask extends AsyncTask<Void, Void, Account> {
471        private final Context mContext;
472        private final String mCheckHost;
473        private final String mCheckLogin;
474
475        public DuplicateCheckTask(Context context, String checkHost, String checkLogin) {
476            mContext = context;
477            mCheckHost = checkHost;
478            mCheckLogin = checkLogin;
479            // Prevent additional clicks on the next button during Async lookup
480            mNextButtonInhibit = true;
481        }
482
483        @Override
484        protected Account doInBackground(Void... params) {
485            EmailContent.Account account = Utility.findExistingAccount(mContext, -1,
486                    mCheckHost, mCheckLogin);
487            return account;
488        }
489
490        @Override
491        protected void onPostExecute(Account duplicateAccount) {
492            mNextButtonInhibit = false;
493            // Exit immediately if the user left before we finished
494            if (mPaused) return;
495            // Show duplicate account warning, or proceed
496            if (duplicateAccount != null) {
497                DuplicateAccountDialogFragment dialogFragment =
498                    DuplicateAccountDialogFragment.newInstance(duplicateAccount.mDisplayName);
499                dialogFragment.show(getFragmentManager(), DuplicateAccountDialogFragment.TAG);
500                return;
501            } else {
502                AccountCheckSettingsFragment checkerFragment =
503                    AccountCheckSettingsFragment.newInstance(
504                        SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING, null);
505                FragmentTransaction transaction = getFragmentManager().beginTransaction();
506                transaction.add(checkerFragment, AccountCheckSettingsFragment.TAG);
507                transaction.addToBackStack("back");
508                transaction.commit();
509            }
510        }
511    }
512
513
514    /**
515     * When "next" button is clicked
516     */
517    private void onNext() {
518        // Try auto-configuration from XML providers (unless in EAS mode, we can skip it)
519        if (SetupData.getFlowMode() != SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) {
520            String email = mEmailView.getText().toString().trim();
521            String[] emailParts = email.split("@");
522            String domain = emailParts[1].trim();
523            mProvider = AccountSettingsUtils.findProviderForDomain(this, domain);
524            if (mProvider != null) {
525                if (mProvider.note != null) {
526                    NoteDialogFragment dialogFragment =
527                            NoteDialogFragment.newInstance(mProvider.note);
528                    dialogFragment.show(getFragmentManager(), NoteDialogFragment.TAG);
529                } else {
530                    finishAutoSetup();
531                }
532                return;
533            }
534        }
535        // Can't use auto setup (although EAS accounts may still be able to AutoDiscover)
536        onManualSetup(true);
537    }
538
539    /**
540     * When "manual setup" button is clicked
541     *
542     * @param allowAutoDiscover - true if the user clicked 'next' and (if the account is EAS)
543     * it's OK to use autodiscover.  false to prevent autodiscover and go straight to manual setup.
544     * Ignored for IMAP & POP accounts.
545     */
546    private void onManualSetup(boolean allowAutoDiscover) {
547        String email = mEmailView.getText().toString().trim();
548        String password = mPasswordView.getText().toString();
549        String[] emailParts = email.split("@");
550        String user = emailParts[0].trim();
551        String domain = emailParts[1].trim();
552
553        // Alternate entry to the debug options screen (for devices without a physical keyboard:
554        //  Username: d@d.d
555        //  Password: debug
556        if (ENTER_DEBUG_SCREEN && "d@d.d".equals(email) && "debug".equals(password)) {
557            mEmailView.setText("");
558            mPasswordView.setText("");
559            AccountSettingsXL.actionSettingsWithDebug(this);
560            return;
561        }
562
563        String uriString = null;
564        try {
565            URI uri = new URI("placeholder", user + ":" + password, domain, -1, null, null, null);
566            uriString = uri.toString();
567        } catch (URISyntaxException use) {
568            // If we can't set up the URL, don't continue - account setup pages will fail too
569            Toast.makeText(this, R.string.account_setup_username_password_toast,
570                    Toast.LENGTH_LONG).show();
571            return;
572        }
573
574        populateSetupData(getOwnerName(), email, mDefaultView.isChecked(), uriString, uriString);
575
576        SetupData.setAllowAutodiscover(allowAutoDiscover);
577        AccountSetupAccountType.actionSelectAccountType(this);
578    }
579
580    /**
581     * To support continuous testing, we allow the forced creation of accounts.
582     * This works in a manner fairly similar to automatic setup, in which the complete server
583     * Uri's are available, except that we will also skip checking (as if both checks were true)
584     * and all other UI.
585     *
586     * @param email The email address for the new account
587     * @param user The user name for the new account
588     * @param incoming The URI-style string defining the incoming account
589     * @param outgoing The URI-style string defining the outgoing account
590     */
591    private void forceCreateAccount(String email, String user, String incoming, String outgoing) {
592        populateSetupData(user, email, false, incoming, outgoing);
593    }
594
595    /**
596     * Populate SetupData's account with complete setup info.
597     */
598    private void populateSetupData(String senderName, String senderEmail, boolean isDefault,
599            String incoming, String outgoing) {
600        Account account = SetupData.getAccount();
601        account.setSenderName(senderName);
602        account.setEmailAddress(senderEmail);
603        account.setDisplayName(senderEmail);
604        account.setDefaultAccount(isDefault);
605        SetupData.setDefault(isDefault);        // TODO - why duplicated, if already set in account
606        account.setStoreUri(this, incoming);
607        account.setSenderUri(this, outgoing);
608
609        // Set sync and delete policies for specific account types
610        if (incoming.startsWith("imap")) {
611            // Delete policy must be set explicitly, because IMAP does not provide a UI selection
612            // for it. This logic needs to be followed in the auto setup flow as well.
613            account.setDeletePolicy(EmailContent.Account.DELETE_POLICY_ON_DELETE);
614        }
615
616        if (incoming.startsWith("eas")) {
617            account.setSyncInterval(Account.CHECK_INTERVAL_PUSH);
618        } else {
619            account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL);
620        }
621    }
622
623    /**
624     * Implements AccountCheckSettingsFragment.Callbacks
625     *
626     * This is used in automatic setup mode to jump directly down to the options screen.
627     */
628    @Override
629    public void onCheckSettingsComplete(int result) {
630        if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) {
631            AccountSetupOptions.actionOptions(this);
632            finish();
633        }
634    }
635
636    /**
637     * Implements AccountCheckSettingsFragment.Callbacks
638     * This is overridden only by AccountSetupExchange
639     */
640    @Override
641    public void onAutoDiscoverComplete(int result, HostAuth hostAuth) {
642        throw new IllegalStateException();
643    }
644
645    /**
646     * AsyncTask checks count of accounts and displays "use this account as default" checkbox
647     * if there are more than one.
648     */
649    private class DisplayCheckboxTask extends AsyncTask<Void, Void, Integer> {
650
651        @Override
652        protected Integer doInBackground(Void... params) {
653            return EmailContent.count(AccountSetupBasics.this, EmailContent.Account.CONTENT_URI);
654        }
655
656        @Override
657        protected void onPostExecute(Integer numAccounts) {
658            if (numAccounts > 0) {
659                Activity activity = AccountSetupBasics.this;
660                activity.findViewById(R.id.account_default_divider_1).setVisibility(View.VISIBLE);
661                mDefaultView.setVisibility(View.VISIBLE);
662                activity.findViewById(R.id.account_default_divider_2).setVisibility(View.VISIBLE);
663            }
664        }
665    }
666
667    private void onEnableProceedButtons(boolean enabled) {
668        mManualButton.setEnabled(enabled);
669        mNextButton.setEnabled(enabled);
670    }
671
672    /**
673     * Dialog fragment to show "setup note" dialog
674     */
675    public static class NoteDialogFragment extends DialogFragment {
676        private final static String TAG = "NoteDialogFragment";
677
678        // Argument bundle keys
679        private final static String BUNDLE_KEY_NOTE = "NoteDialogFragment.Note";
680
681        /**
682         * Create the dialog with parameters
683         */
684        public static NoteDialogFragment newInstance(String note) {
685            NoteDialogFragment f = new NoteDialogFragment();
686            Bundle b = new Bundle();
687            b.putString(BUNDLE_KEY_NOTE, note);
688            f.setArguments(b);
689            return f;
690        }
691
692        @Override
693        public Dialog onCreateDialog(Bundle savedInstanceState) {
694            Context context = getActivity();
695            final String note = getArguments().getString(BUNDLE_KEY_NOTE);
696
697            return new AlertDialog.Builder(context)
698                .setIconAttribute(android.R.attr.alertDialogIcon)
699                .setTitle(android.R.string.dialog_alert_title)
700                .setMessage(note)
701                .setPositiveButton(
702                        R.string.okay_action,
703                        new DialogInterface.OnClickListener() {
704                            public void onClick(DialogInterface dialog, int which) {
705                                Activity a = getActivity();
706                                if (a instanceof AccountSetupBasics) {
707                                    ((AccountSetupBasics)a).finishAutoSetup();
708                                }
709                                dismiss();
710                            }
711                        })
712                .setNegativeButton(
713                        context.getString(R.string.cancel_action),
714                        null)
715                .create();
716        }
717    }
718}
719