AccountSetupIncomingFragment.java revision 8989dfa5e7213a42362b3bbdf865b46dab5a5012
1/*
2 * Copyright (C) 2010 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 android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.content.Loader;
23import android.net.Uri;
24import android.os.Bundle;
25import android.os.Parcel;
26import android.text.Editable;
27import android.text.TextUtils;
28import android.text.TextWatcher;
29import android.text.method.DigitsKeyListener;
30import android.view.LayoutInflater;
31import android.view.View;
32import android.view.ViewGroup;
33import android.view.inputmethod.EditorInfo;
34import android.widget.AdapterView;
35import android.widget.ArrayAdapter;
36import android.widget.EditText;
37import android.widget.Spinner;
38import android.widget.TextView;
39
40import com.android.email.R;
41import com.android.email.activity.UiUtilities;
42import com.android.email.activity.setup.AuthenticationView.AuthenticationCallback;
43import com.android.email.provider.AccountBackupRestore;
44import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
45import com.android.email.view.CertificateSelector;
46import com.android.email.view.CertificateSelector.HostCallback;
47import com.android.emailcommon.Device;
48import com.android.emailcommon.provider.Account;
49import com.android.emailcommon.provider.Credential;
50import com.android.emailcommon.provider.HostAuth;
51import com.android.emailcommon.utility.CertificateRequestor;
52import com.android.emailcommon.utility.Utility;
53import com.android.mail.ui.MailAsyncTaskLoader;
54import com.android.mail.utils.LogUtils;
55
56import java.io.IOException;
57import java.util.ArrayList;
58
59/**
60 * Provides UI for IMAP/POP account settings.
61 *
62 * This fragment is used by AccountSetupIncoming (for creating accounts) and by AccountSettingsXL
63 * (for editing existing accounts).
64 */
65public class AccountSetupIncomingFragment extends AccountServerBaseFragment
66        implements HostCallback, AuthenticationCallback {
67
68    private static final int CERTIFICATE_REQUEST = 0;
69    private static final int SIGN_IN_REQUEST = 1;
70
71    private final static String STATE_KEY_CREDENTIAL = "AccountSetupIncomingFragment.credential";
72    private final static String STATE_KEY_LOADED = "AccountSetupIncomingFragment.loaded";
73
74    private EditText mUsernameView;
75    private AuthenticationView mAuthenticationView;
76    private TextView mAuthenticationLabel;
77    private TextView mServerLabelView;
78    private EditText mServerView;
79    private EditText mPortView;
80    private Spinner mSecurityTypeView;
81    private TextView mDeletePolicyLabelView;
82    private Spinner mDeletePolicyView;
83    private CertificateSelector mClientCertificateSelector;
84    private View mDeviceIdSection;
85    private View mImapPathPrefixSectionView;
86    private EditText mImapPathPrefixView;
87    // Delete policy as loaded from the device
88    private int mLoadedDeletePolicy;
89
90    private TextWatcher mValidationTextWatcher;
91
92    // Support for lifecycle
93    private boolean mLoaded;
94    private String mCacheLoginCredential;
95    private EmailServiceInfo mServiceInfo;
96
97    public static AccountSetupIncomingFragment newInstance(boolean settingsMode) {
98        final AccountSetupIncomingFragment f = new AccountSetupIncomingFragment();
99        f.setArguments(getArgs(settingsMode));
100        return f;
101    }
102
103    // Public no-args constructor needed for fragment re-instantiation
104    public AccountSetupIncomingFragment() {}
105
106    /**
107     * Called to do initial creation of a fragment.  This is called after
108     * {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}.
109     */
110    @Override
111    public void onCreate(Bundle savedInstanceState) {
112        super.onCreate(savedInstanceState);
113
114        if (savedInstanceState != null) {
115            mCacheLoginCredential = savedInstanceState.getString(STATE_KEY_CREDENTIAL);
116            mLoaded = savedInstanceState.getBoolean(STATE_KEY_LOADED, false);
117        }
118    }
119
120    @Override
121    public View onCreateView(LayoutInflater inflater, ViewGroup container,
122            Bundle savedInstanceState) {
123        final View view;
124        if (mSettingsMode) {
125            view = inflater.inflate(R.layout.account_settings_incoming_fragment, container, false);
126        } else {
127            view = inflateTemplatedView(inflater, container,
128                    R.layout.account_setup_incoming_fragment,
129                    R.string.account_setup_incoming_headline);
130        }
131
132        mUsernameView = UiUtilities.getView(view, R.id.account_username);
133        mServerLabelView = UiUtilities.getView(view, R.id.account_server_label);
134        mServerView = UiUtilities.getView(view, R.id.account_server);
135        mPortView = UiUtilities.getView(view, R.id.account_port);
136        mSecurityTypeView = UiUtilities.getView(view, R.id.account_security_type);
137        mDeletePolicyLabelView = UiUtilities.getView(view, R.id.account_delete_policy_label);
138        mDeletePolicyView = UiUtilities.getView(view, R.id.account_delete_policy);
139        mImapPathPrefixSectionView = UiUtilities.getView(view, R.id.imap_path_prefix_section);
140        mImapPathPrefixView = UiUtilities.getView(view, R.id.imap_path_prefix);
141        mAuthenticationView = UiUtilities.getView(view, R.id.authentication_view);
142        mClientCertificateSelector = UiUtilities.getView(view, R.id.client_certificate_selector);
143        mDeviceIdSection = UiUtilities.getView(view, R.id.device_id_section);
144        // Don't use UiUtilities here. In some configurations this view does not exist, and
145        // UiUtilities throws an exception in this case.
146        mAuthenticationLabel = (TextView)view.findViewById(R.id.authentication_label);
147
148        // Updates the port when the user changes the security type. This allows
149        // us to show a reasonable default which the user can change.
150        mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
151            @Override
152            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
153                updatePortFromSecurityType();
154            }
155
156            @Override
157            public void onNothingSelected(AdapterView<?> arg0) { }
158        });
159
160        // After any text edits, call validateFields() which enables or disables the Next button
161        mValidationTextWatcher = new TextWatcher() {
162            @Override
163            public void afterTextChanged(Editable s) {
164                validateFields();
165            }
166
167            @Override
168            public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
169            @Override
170            public void onTextChanged(CharSequence s, int start, int before, int count) { }
171        };
172        // We're editing an existing account; don't allow modification of the user name
173        if (mSettingsMode) {
174            makeTextViewUneditable(mUsernameView,
175                    getString(R.string.account_setup_username_uneditable_error));
176        }
177        mUsernameView.addTextChangedListener(mValidationTextWatcher);
178        mServerView.addTextChangedListener(mValidationTextWatcher);
179        mPortView.addTextChangedListener(mValidationTextWatcher);
180
181        // Only allow digits in the port field.
182        mPortView.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
183
184        // Additional setup only used while in "settings" mode
185        onCreateViewSettingsMode(view);
186
187        mAuthenticationView.setAuthenticationCallback(this);
188
189        return view;
190    }
191
192    @Override
193    public void onActivityCreated(Bundle savedInstanceState) {
194        super.onActivityCreated(savedInstanceState);
195        mClientCertificateSelector.setHostCallback(this);
196
197        final Context context = getActivity();
198        final SetupDataFragment.SetupDataContainer container =
199                (SetupDataFragment.SetupDataContainer) context;
200        mSetupData = container.getSetupData();
201        final Account account = mSetupData.getAccount();
202        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext);
203
204        // Pre-fill info as appropriate
205        if (!mSetupData.isIncomingCredLoaded()) {
206            recvAuth.mLogin = mSetupData.getEmail();
207            AccountSetupCredentialsFragment.populateHostAuthWithResults(context, recvAuth,
208                    mSetupData.getCredentialResults());
209            final String[] emailParts = mSetupData.getEmail().split("@");
210            final String domain = emailParts[1];
211            recvAuth.setConnection(recvAuth.mProtocol, domain, HostAuth.PORT_UNKNOWN,
212                    HostAuth.FLAG_NONE);
213            mSetupData.setIncomingCredLoaded(true);
214        }
215
216        mServiceInfo = mSetupData.getIncomingServiceInfo(context);
217
218        if (mServiceInfo.offerLocalDeletes) {
219            SpinnerOption deletePolicies[] = {
220                    new SpinnerOption(Account.DELETE_POLICY_NEVER,
221                            context.getString(
222                                    R.string.account_setup_incoming_delete_policy_never_label)),
223                    new SpinnerOption(Account.DELETE_POLICY_ON_DELETE,
224                            context.getString(
225                                    R.string.account_setup_incoming_delete_policy_delete_label)),
226            };
227            ArrayAdapter<SpinnerOption> deletePoliciesAdapter =
228                    new ArrayAdapter<SpinnerOption>(context,
229                            android.R.layout.simple_spinner_item, deletePolicies);
230            deletePoliciesAdapter.setDropDownViewResource(
231                    android.R.layout.simple_spinner_dropdown_item);
232            mDeletePolicyView.setAdapter(deletePoliciesAdapter);
233        }
234
235        // Set up security type spinner
236        ArrayList<SpinnerOption> securityTypes = new ArrayList<SpinnerOption>();
237        securityTypes.add(
238                new SpinnerOption(HostAuth.FLAG_NONE, context.getString(
239                        R.string.account_setup_incoming_security_none_label)));
240        securityTypes.add(
241                new SpinnerOption(HostAuth.FLAG_SSL, context.getString(
242                        R.string.account_setup_incoming_security_ssl_label)));
243        securityTypes.add(
244                new SpinnerOption(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, context.getString(
245                        R.string.account_setup_incoming_security_ssl_trust_certificates_label)));
246        if (mServiceInfo.offerTls) {
247            securityTypes.add(
248                    new SpinnerOption(HostAuth.FLAG_TLS, context.getString(
249                            R.string.account_setup_incoming_security_tls_label)));
250            securityTypes.add(new SpinnerOption(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL,
251                    context.getString(R.string
252                            .account_setup_incoming_security_tls_trust_certificates_label)));
253        }
254        ArrayAdapter<SpinnerOption> securityTypesAdapter = new ArrayAdapter<SpinnerOption>(
255                context, android.R.layout.simple_spinner_item, securityTypes);
256        securityTypesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
257        mSecurityTypeView.setAdapter(securityTypesAdapter);
258
259        configureEditor();
260        loadSettings();
261    }
262
263    /**
264     * Called when the fragment is visible to the user and actively running.
265     */
266    @Override
267    public void onResume() {
268        super.onResume();
269        validateFields();
270    }
271
272    @Override
273    public void onDestroyView() {
274        // Make sure we don't get callbacks after the views are supposed to be destroyed
275        // and also don't hold onto them longer than we need
276        if (mUsernameView != null) {
277            mUsernameView.removeTextChangedListener(mValidationTextWatcher);
278        }
279        mUsernameView = null;
280        mServerLabelView = null;
281        if (mServerView != null) {
282            mServerView.removeTextChangedListener(mValidationTextWatcher);
283        }
284        mServerView = null;
285        if (mPortView != null) {
286            mPortView.removeTextChangedListener(mValidationTextWatcher);
287        }
288        mPortView = null;
289        if (mSecurityTypeView != null) {
290            mSecurityTypeView.setOnItemSelectedListener(null);
291        }
292        mSecurityTypeView = null;
293        mDeletePolicyLabelView = null;
294        mDeletePolicyView = null;
295        mImapPathPrefixSectionView = null;
296        mImapPathPrefixView = null;
297        mDeviceIdSection = null;
298        mClientCertificateSelector = null;
299
300        super.onDestroyView();
301    }
302
303    @Override
304    public void onSaveInstanceState(Bundle outState) {
305        super.onSaveInstanceState(outState);
306
307        outState.putString(STATE_KEY_CREDENTIAL, mCacheLoginCredential);
308        outState.putBoolean(STATE_KEY_LOADED, mLoaded);
309    }
310
311    /**
312     * Configure the editor for the account type
313     */
314    private void configureEditor() {
315        final Account account = mSetupData.getAccount();
316        if (account == null || account.mHostAuthRecv == null) {
317            LogUtils.e(LogUtils.TAG,
318                    "null account or host auth. account null: %b host auth null: %b",
319                    account == null, account == null || account.mHostAuthRecv == null);
320            return;
321        }
322        mBaseScheme = account.mHostAuthRecv.mProtocol;
323        mServerLabelView.setText(R.string.account_setup_incoming_server_label);
324        mServerView.setContentDescription(getResources().getText(
325                R.string.account_setup_incoming_server_label));
326        if (!mServiceInfo.offerPrefix) {
327            mImapPathPrefixSectionView.setVisibility(View.GONE);
328        }
329        if (!mServiceInfo.offerLocalDeletes) {
330            mDeletePolicyLabelView.setVisibility(View.GONE);
331            mDeletePolicyView.setVisibility(View.GONE);
332            mPortView.setImeOptions(EditorInfo.IME_ACTION_NEXT);
333        }
334    }
335
336    /**
337     * Load the current settings into the UI
338     */
339    private void loadSettings() {
340        if (mLoaded) return;
341
342        final Account account = mSetupData.getAccount();
343        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext);
344        mServiceInfo = mSetupData.getIncomingServiceInfo(getActivity());
345        mAuthenticationView.setAuthInfo(mServiceInfo.offerOAuth, recvAuth);
346        if (mAuthenticationLabel != null) {
347            if (mServiceInfo.offerOAuth) {
348                mAuthenticationLabel.setText(R.string.authentication_label);
349            } else {
350                mAuthenticationLabel.setText(R.string.account_setup_basics_password_label);
351            }
352        }
353
354        final String username = recvAuth.mLogin;
355        if (username != null) {
356            //*** For eas?
357            // Add a backslash to the start of the username, but only if the username has no
358            // backslash in it.
359            //if (userName.indexOf('\\') < 0) {
360            //    userName = "\\" + userName;
361            //}
362            mUsernameView.setText(username);
363        }
364
365        if (mServiceInfo.offerPrefix) {
366            final String prefix = recvAuth.mDomain;
367            if (prefix != null && prefix.length() > 0) {
368                mImapPathPrefixView.setText(prefix.substring(1));
369            }
370        }
371
372        // The delete policy is set for all legacy accounts. For POP3 accounts, the user sets
373        // the policy explicitly. For IMAP accounts, the policy is set when the Account object
374        // is created. @see AccountSetupBasics#populateSetupData
375        mLoadedDeletePolicy = account.getDeletePolicy();
376        SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy);
377
378        int flags = recvAuth.mFlags;
379        if (mServiceInfo.defaultSsl) {
380            flags |= HostAuth.FLAG_SSL;
381        }
382        // Strip out any flags that are not related to security type.
383        int securityTypeFlags = (flags & HostAuth.FLAG_TRANSPORTSECURITY_MASK);
384        SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, securityTypeFlags);
385
386        final String hostname = recvAuth.mAddress;
387        if (hostname != null) {
388            mServerView.setText(hostname);
389        }
390
391        final int port = recvAuth.mPort;
392        if (port != HostAuth.PORT_UNKNOWN) {
393            mPortView.setText(Integer.toString(port));
394        } else {
395            updatePortFromSecurityType();
396        }
397
398        if (recvAuth.mClientCertAlias != null) {
399            mClientCertificateSelector.setCertificate(recvAuth.mClientCertAlias);
400        }
401
402        // Make a deep copy of the HostAuth to compare with later
403        final Parcel parcel = Parcel.obtain();
404        parcel.writeParcelable(recvAuth, recvAuth.describeContents());
405        parcel.setDataPosition(0);
406        mLoadedRecvAuth = parcel.readParcelable(HostAuth.class.getClassLoader());
407        parcel.recycle();
408
409        mLoaded = true;
410        validateFields();
411    }
412
413    /**
414     * Check the values in the fields and decide if it makes sense to enable the "next" button
415     */
416    private void validateFields() {
417        if (!mLoaded) return;
418        enableNextButton(!TextUtils.isEmpty(mUsernameView.getText())
419                && mAuthenticationView.getAuthValid()
420                && Utility.isServerNameValid(mServerView)
421                && Utility.isPortFieldValid(mPortView));
422
423        mCacheLoginCredential = mUsernameView.getText().toString().trim();
424    }
425
426    private int getPortFromSecurityType(boolean useSsl) {
427        return useSsl ? mServiceInfo.portSsl : mServiceInfo.port;
428    }
429
430    private boolean getSslSelected() {
431        final int securityType =
432                (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
433        return ((securityType & HostAuth.FLAG_SSL) != 0);
434    }
435
436    public void onUseSslChanged(boolean useSsl) {
437        if (mServiceInfo.offerCerts) {
438            final int mode = useSsl ? View.VISIBLE : View.GONE;
439            mClientCertificateSelector.setVisibility(mode);
440            String deviceId = "";
441            try {
442                deviceId = Device.getDeviceId(mAppContext);
443            } catch (IOException e) {
444                // Not required
445            }
446            ((TextView) UiUtilities.getView(getView(), R.id.device_id)).setText(deviceId);
447
448            mDeviceIdSection.setVisibility(mode);
449        }
450    }
451
452    private void updatePortFromSecurityType() {
453        final boolean sslSelected = getSslSelected();
454        final int port = getPortFromSecurityType(sslSelected);
455        mPortView.setText(Integer.toString(port));
456        onUseSslChanged(sslSelected);
457    }
458
459    @Override
460    public void saveSettings() {
461        // Reset this here so we don't get stuck on this screen
462        mLoadedDeletePolicy = mSetupData.getAccount().getDeletePolicy();
463        super.saveSettings();
464    }
465
466    private static class SaveSettingsLoader extends MailAsyncTaskLoader<Boolean> {
467        private final SetupDataFragment mSetupData;
468        private final boolean mSettingsMode;
469
470        private SaveSettingsLoader(Context context, SetupDataFragment setupData,
471                boolean settingsMode) {
472            super(context);
473            mSetupData = setupData;
474            mSettingsMode = settingsMode;
475        }
476
477        @Override
478        public Boolean loadInBackground() {
479            if (mSettingsMode) {
480                saveSettingsAfterEdit(getContext(), mSetupData);
481            } else {
482                saveSettingsAfterSetup(getContext(), mSetupData);
483            }
484            return true;
485        }
486
487        @Override
488        protected void onDiscardResult(Boolean result) {}
489    }
490
491    @Override
492    public Loader<Boolean> getSaveSettingsLoader() {
493        return new SaveSettingsLoader(mAppContext, mSetupData, mSettingsMode);
494    }
495
496    /**
497     * Entry point from Activity after editing settings and verifying them.  Must be FLOW_MODE_EDIT.
498     * Note, we update account here (as well as the account.mHostAuthRecv) because we edit
499     * account's delete policy here.
500     * Blocking - do not call from UI Thread.
501     */
502    public static void saveSettingsAfterEdit(Context context, SetupDataFragment setupData) {
503        final Account account = setupData.getAccount();
504        account.update(context, account.toContentValues());
505        final Credential cred = account.mHostAuthRecv.mCredential;
506        if (cred != null) {
507            if (cred.isSaved()) {
508                cred.update(context, cred.toContentValues());
509            } else {
510                cred.save(context);
511                account.mHostAuthRecv.mCredentialKey = cred.mId;
512            }
513        }
514        account.mHostAuthRecv.update(context, account.mHostAuthRecv.toContentValues());
515        // Update the backup (side copy) of the accounts
516        AccountBackupRestore.backup(context);
517    }
518
519    /**
520     * Entry point from Activity after entering new settings and verifying them.  For setup mode.
521     */
522    public static void saveSettingsAfterSetup(Context context, SetupDataFragment setupData) {
523        final Account account = setupData.getAccount();
524        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(context);
525        final HostAuth sendAuth = account.getOrCreateHostAuthSend(context);
526
527        // Set the username and password for the outgoing settings to the username and
528        // password the user just set for incoming.  Use the verified host address to try and
529        // pick a smarter outgoing address.
530        final String hostName =
531                AccountSettingsUtils.inferServerName(context, recvAuth.mAddress, null, "smtp");
532        sendAuth.setLogin(recvAuth.mLogin, recvAuth.mPassword);
533        sendAuth.setConnection(sendAuth.mProtocol, hostName, sendAuth.mPort, sendAuth.mFlags);
534    }
535
536    /**
537     * Entry point from Activity, when "next" button is clicked
538     */
539    @Override
540    public int collectUserInputInternal() {
541        final Account account = mSetupData.getAccount();
542
543        // Make sure delete policy is an valid option before using it; otherwise, the results are
544        // indeterminate, I suspect...
545        if (mDeletePolicyView.getVisibility() == View.VISIBLE) {
546            account.setDeletePolicy(
547                    (Integer) ((SpinnerOption) mDeletePolicyView.getSelectedItem()).value);
548        }
549
550        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext);
551        final String userName = mUsernameView.getText().toString().trim();
552        final String userPassword = mAuthenticationView.getPassword();
553        recvAuth.setLogin(userName, userPassword);
554        if (!TextUtils.isEmpty(mAuthenticationView.getOAuthProvider())) {
555            Credential cred = recvAuth.getOrCreateCredential(getActivity());
556            cred.mProviderId = mAuthenticationView.getOAuthProvider();
557        }
558
559        final String serverAddress = mServerView.getText().toString().trim();
560        int serverPort;
561        try {
562            serverPort = Integer.parseInt(mPortView.getText().toString().trim());
563        } catch (NumberFormatException e) {
564            serverPort = getPortFromSecurityType(getSslSelected());
565            LogUtils.d(LogUtils.TAG, "Non-integer server port; using '" + serverPort + "'");
566        }
567        final int securityType =
568                (Integer) ((SpinnerOption) mSecurityTypeView.getSelectedItem()).value;
569        recvAuth.setConnection(mBaseScheme, serverAddress, serverPort, securityType);
570        if (mServiceInfo.offerPrefix) {
571            final String prefix = mImapPathPrefixView.getText().toString().trim();
572            recvAuth.mDomain = TextUtils.isEmpty(prefix) ? null : ("/" + prefix);
573        } else {
574            recvAuth.mDomain = null;
575        }
576        recvAuth.mClientCertAlias = mClientCertificateSelector.getCertificate();
577
578        return SetupDataFragment.CHECK_INCOMING;
579    }
580
581    @Override
582    public boolean haveSettingsChanged() {
583        final boolean deletePolicyChanged;
584
585        // Only verify the delete policy if the control is visible (i.e. is a pop3 account)
586        if (mDeletePolicyView != null && mDeletePolicyView.getVisibility() == View.VISIBLE) {
587            int newDeletePolicy =
588                (Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value;
589            deletePolicyChanged = mLoadedDeletePolicy != newDeletePolicy;
590        } else {
591            deletePolicyChanged = false;
592        }
593
594        return deletePolicyChanged || super.haveSettingsChanged();
595    }
596
597    @Override
598    public void onValidateStateChanged() {
599        validateFields();
600    }
601
602    @Override
603    public void onRequestSignIn() {
604        // Launch the credentials activity.
605        final String protocol =
606                mSetupData.getAccount().getOrCreateHostAuthRecv(mAppContext).mProtocol;
607        final Intent intent = AccountCredentials.getAccountCredentialsIntent(getActivity(),
608                mUsernameView.getText().toString(), protocol);
609        startActivityForResult(intent, SIGN_IN_REQUEST);
610    }
611
612    @Override
613    public void onCertificateRequested() {
614        final Intent intent = new Intent(CertificateRequestor.ACTION_REQUEST_CERT);
615        intent.setData(Uri.parse("eas://com.android.emailcommon/certrequest"));
616        startActivityForResult(intent, CERTIFICATE_REQUEST);
617    }
618
619    @Override
620    public void onActivityResult(int requestCode, int resultCode, Intent data) {
621        if (requestCode == CERTIFICATE_REQUEST && resultCode == Activity.RESULT_OK) {
622            final String certAlias = data.getStringExtra(CertificateRequestor.RESULT_ALIAS);
623            if (certAlias != null) {
624                mClientCertificateSelector.setCertificate(certAlias);
625            }
626        } else if (requestCode == SIGN_IN_REQUEST && resultCode == Activity.RESULT_OK) {
627            final Account account = mSetupData.getAccount();
628            final HostAuth recvAuth = account.getOrCreateHostAuthRecv(getActivity());
629            AccountSetupCredentialsFragment.populateHostAuthWithResults(mAppContext, recvAuth,
630                    data.getExtras());
631            mAuthenticationView.setAuthInfo(mServiceInfo.offerOAuth, recvAuth);
632        }
633    }
634}
635