AccountSetupIncomingFragment.java revision 6ecdc1845778367f3c72d8f31cc63026539004d7
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.text.Editable;
26import android.text.TextUtils;
27import android.text.TextWatcher;
28import android.text.method.DigitsKeyListener;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.inputmethod.EditorInfo;
33import android.widget.AdapterView;
34import android.widget.ArrayAdapter;
35import android.widget.EditText;
36import android.widget.Spinner;
37import android.widget.TextView;
38
39import com.android.email.R;
40import com.android.email.activity.UiUtilities;
41import com.android.email.activity.setup.AuthenticationView.AuthenticationCallback;
42import com.android.email.provider.AccountBackupRestore;
43import com.android.email.service.EmailServiceUtils;
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 int layoutId = mSettingsMode
124                ? R.layout.account_settings_incoming_fragment
125                : R.layout.account_setup_incoming_fragment;
126
127        final View view = inflater.inflate(layoutId, container, false);
128
129        mUsernameView = UiUtilities.getView(view, R.id.account_username);
130        mServerLabelView = UiUtilities.getView(view, R.id.account_server_label);
131        mServerView = UiUtilities.getView(view, R.id.account_server);
132        mPortView = UiUtilities.getView(view, R.id.account_port);
133        mSecurityTypeView = UiUtilities.getView(view, R.id.account_security_type);
134        mDeletePolicyLabelView = UiUtilities.getView(view, R.id.account_delete_policy_label);
135        mDeletePolicyView = UiUtilities.getView(view, R.id.account_delete_policy);
136        mImapPathPrefixSectionView = UiUtilities.getView(view, R.id.imap_path_prefix_section);
137        mImapPathPrefixView = UiUtilities.getView(view, R.id.imap_path_prefix);
138        mAuthenticationView = UiUtilities.getView(view, R.id.authentication_view);
139        mClientCertificateSelector = UiUtilities.getView(view, R.id.client_certificate_selector);
140        mDeviceIdSection = UiUtilities.getView(view, R.id.device_id_section);
141        // Don't use UiUtilities here. In some configurations this view does not exist, and
142        // UiUtilities throws an exception in this case.
143        mAuthenticationLabel = (TextView)view.findViewById(R.id.authentication_label);
144
145        // Updates the port when the user changes the security type. This allows
146        // us to show a reasonable default which the user can change.
147        mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
148            @Override
149            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
150                updatePortFromSecurityType();
151            }
152
153            @Override
154            public void onNothingSelected(AdapterView<?> arg0) { }
155        });
156
157        // After any text edits, call validateFields() which enables or disables the Next button
158        mValidationTextWatcher = new TextWatcher() {
159            @Override
160            public void afterTextChanged(Editable s) {
161                validateFields();
162            }
163
164            @Override
165            public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
166            @Override
167            public void onTextChanged(CharSequence s, int start, int before, int count) { }
168        };
169        // We're editing an existing account; don't allow modification of the user name
170        if (mSettingsMode) {
171            makeTextViewUneditable(mUsernameView,
172                    getString(R.string.account_setup_username_uneditable_error));
173        }
174        mUsernameView.addTextChangedListener(mValidationTextWatcher);
175        mServerView.addTextChangedListener(mValidationTextWatcher);
176        mPortView.addTextChangedListener(mValidationTextWatcher);
177
178        // Only allow digits in the port field.
179        mPortView.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
180
181        // Additional setup only used while in "settings" mode
182        onCreateViewSettingsMode(view);
183
184        mAuthenticationView.setAuthenticationCallback(this);
185
186        return view;
187    }
188
189    @Override
190    public void onActivityCreated(Bundle savedInstanceState) {
191        super.onActivityCreated(savedInstanceState);
192        mClientCertificateSelector.setHostCallback(this);
193
194        final Context context = getActivity();
195        final SetupDataFragment.SetupDataContainer container =
196                (SetupDataFragment.SetupDataContainer) context;
197        mSetupData = container.getSetupData();
198        final Account account = mSetupData.getAccount();
199        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext);
200
201        // Pre-fill info as appropriate
202        if (!mSetupData.isIncomingCredLoaded()) {
203            recvAuth.mLogin = mSetupData.getEmail();
204            AccountSetupCredentialsFragment.populateHostAuthWithResults(context, recvAuth,
205                    mSetupData.getCredentialResults());
206            final String[] emailParts = mSetupData.getEmail().split("@");
207            final String domain = emailParts[1];
208            recvAuth.setConnection(recvAuth.mProtocol, domain, HostAuth.PORT_UNKNOWN,
209                    HostAuth.FLAG_NONE);
210            mSetupData.setIncomingCredLoaded(true);
211        }
212
213        mServiceInfo = EmailServiceUtils.getServiceInfo(mAppContext, recvAuth.mProtocol);
214
215        if (mServiceInfo.offerLocalDeletes) {
216            SpinnerOption deletePolicies[] = {
217                    new SpinnerOption(Account.DELETE_POLICY_NEVER,
218                            context.getString(
219                                    R.string.account_setup_incoming_delete_policy_never_label)),
220                    new SpinnerOption(Account.DELETE_POLICY_ON_DELETE,
221                            context.getString(
222                                    R.string.account_setup_incoming_delete_policy_delete_label)),
223            };
224            ArrayAdapter<SpinnerOption> deletePoliciesAdapter =
225                    new ArrayAdapter<SpinnerOption>(context,
226                            android.R.layout.simple_spinner_item, deletePolicies);
227            deletePoliciesAdapter.setDropDownViewResource(
228                    android.R.layout.simple_spinner_dropdown_item);
229            mDeletePolicyView.setAdapter(deletePoliciesAdapter);
230        }
231
232        // Set up security type spinner
233        ArrayList<SpinnerOption> securityTypes = new ArrayList<SpinnerOption>();
234        securityTypes.add(
235                new SpinnerOption(HostAuth.FLAG_NONE, context.getString(
236                        R.string.account_setup_incoming_security_none_label)));
237        securityTypes.add(
238                new SpinnerOption(HostAuth.FLAG_SSL, context.getString(
239                        R.string.account_setup_incoming_security_ssl_label)));
240        securityTypes.add(
241                new SpinnerOption(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, context.getString(
242                        R.string.account_setup_incoming_security_ssl_trust_certificates_label)));
243        if (mServiceInfo.offerTls) {
244            securityTypes.add(
245                    new SpinnerOption(HostAuth.FLAG_TLS, context.getString(
246                            R.string.account_setup_incoming_security_tls_label)));
247            securityTypes.add(new SpinnerOption(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL,
248                    context.getString(R.string
249                            .account_setup_incoming_security_tls_trust_certificates_label)));
250        }
251        ArrayAdapter<SpinnerOption> securityTypesAdapter = new ArrayAdapter<SpinnerOption>(
252                context, android.R.layout.simple_spinner_item, securityTypes);
253        securityTypesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
254        mSecurityTypeView.setAdapter(securityTypesAdapter);
255
256        configureEditor();
257        loadSettings();
258    }
259
260    /**
261     * Called when the fragment is visible to the user and actively running.
262     */
263    @Override
264    public void onResume() {
265        super.onResume();
266        validateFields();
267    }
268
269    @Override
270    public void onDestroyView() {
271        // Make sure we don't get callbacks after the views are supposed to be destroyed
272        // and also don't hold onto them longer than we need
273        if (mUsernameView != null) {
274            mUsernameView.removeTextChangedListener(mValidationTextWatcher);
275        }
276        mUsernameView = null;
277        mServerLabelView = null;
278        if (mServerView != null) {
279            mServerView.removeTextChangedListener(mValidationTextWatcher);
280        }
281        mServerView = null;
282        if (mPortView != null) {
283            mPortView.removeTextChangedListener(mValidationTextWatcher);
284        }
285        mPortView = null;
286        if (mSecurityTypeView != null) {
287            mSecurityTypeView.setOnItemSelectedListener(null);
288        }
289        mSecurityTypeView = null;
290        mDeletePolicyLabelView = null;
291        mDeletePolicyView = null;
292        mImapPathPrefixSectionView = null;
293        mImapPathPrefixView = null;
294        mDeviceIdSection = null;
295        mClientCertificateSelector = null;
296
297        super.onDestroyView();
298    }
299
300    @Override
301    public void onSaveInstanceState(Bundle outState) {
302        super.onSaveInstanceState(outState);
303
304        outState.putString(STATE_KEY_CREDENTIAL, mCacheLoginCredential);
305        outState.putBoolean(STATE_KEY_LOADED, mLoaded);
306    }
307
308    /**
309     * Configure the editor for the account type
310     */
311    private void configureEditor() {
312        final Account account = mSetupData.getAccount();
313        if (account == null || account.mHostAuthRecv == null) {
314            LogUtils.e(LogUtils.TAG,
315                    "null account or host auth. account null: %b host auth null: %b",
316                    account == null, account == null || account.mHostAuthRecv == null);
317            return;
318        }
319        TextView lastView = mImapPathPrefixView;
320        mBaseScheme = account.mHostAuthRecv.mProtocol;
321        mServerLabelView.setText(R.string.account_setup_incoming_server_label);
322        mServerView.setContentDescription(getResources().getText(
323                R.string.account_setup_incoming_server_label));
324        if (!mServiceInfo.offerPrefix) {
325            mImapPathPrefixSectionView.setVisibility(View.GONE);
326            lastView = mPortView;
327        }
328        if (!mServiceInfo.offerLocalDeletes) {
329            mDeletePolicyLabelView.setVisibility(View.GONE);
330            mDeletePolicyView.setVisibility(View.GONE);
331            mPortView.setImeOptions(EditorInfo.IME_ACTION_NEXT);
332        }
333        lastView.setOnEditorActionListener(mDismissImeOnDoneListener);
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 = EmailServiceUtils.getServiceInfo(mAppContext, recvAuth.mProtocol);
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.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        mLoadedRecvAuth = recvAuth;
403        mLoaded = true;
404        validateFields();
405    }
406
407    /**
408     * Check the values in the fields and decide if it makes sense to enable the "next" button
409     */
410    private void validateFields() {
411        if (!mLoaded) return;
412        enableNextButton(!TextUtils.isEmpty(mUsernameView.getText())
413                && mAuthenticationView.getAuthValid()
414                && Utility.isServerNameValid(mServerView)
415                && Utility.isPortFieldValid(mPortView));
416
417        mCacheLoginCredential = mUsernameView.getText().toString().trim();
418    }
419
420    private int getPortFromSecurityType(boolean useSsl) {
421        final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(mAppContext,
422                mSetupData.getAccount().mHostAuthRecv.mProtocol);
423        return useSsl ? info.portSsl : info.port;
424    }
425
426    private boolean getSslSelected() {
427        final int securityType =
428                (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
429        return ((securityType & HostAuth.FLAG_SSL) != 0);
430    }
431
432    public void onUseSslChanged(boolean useSsl) {
433        if (mServiceInfo.offerCerts) {
434            final int mode = useSsl ? View.VISIBLE : View.GONE;
435            mClientCertificateSelector.setVisibility(mode);
436            String deviceId = "";
437            try {
438                deviceId = Device.getDeviceId(mAppContext);
439            } catch (IOException e) {
440                // Not required
441            }
442            ((TextView) UiUtilities.getView(getView(), R.id.device_id)).setText(deviceId);
443
444            mDeviceIdSection.setVisibility(mode);
445        }
446    }
447
448    private void updatePortFromSecurityType() {
449        final boolean sslSelected = getSslSelected();
450        final int port = getPortFromSecurityType(sslSelected);
451        mPortView.setText(Integer.toString(port));
452        onUseSslChanged(sslSelected);
453    }
454
455    private static class SaveSettingsLoader extends MailAsyncTaskLoader<Boolean> {
456        private final SetupDataFragment mSetupData;
457        private final boolean mSettingsMode;
458
459        private SaveSettingsLoader(Context context, SetupDataFragment setupData,
460                boolean settingsMode) {
461            super(context);
462            mSetupData = setupData;
463            mSettingsMode = settingsMode;
464        }
465
466        @Override
467        public Boolean loadInBackground() {
468            if (mSettingsMode) {
469                saveSettingsAfterEdit(getContext(), mSetupData);
470            } else {
471                saveSettingsAfterSetup(getContext(), mSetupData);
472            }
473            return true;
474        }
475
476        @Override
477        protected void onDiscardResult(Boolean result) {}
478    }
479
480    @Override
481    public Loader<Boolean> getSaveSettingsLoader() {
482        return new SaveSettingsLoader(mAppContext, mSetupData, mSettingsMode);
483    }
484
485    /**
486     * Entry point from Activity after editing settings and verifying them.  Must be FLOW_MODE_EDIT.
487     * Note, we update account here (as well as the account.mHostAuthRecv) because we edit
488     * account's delete policy here.
489     * Blocking - do not call from UI Thread.
490     */
491    public static void saveSettingsAfterEdit(Context context, SetupDataFragment setupData) {
492        final Account account = setupData.getAccount();
493        account.update(context, account.toContentValues());
494        final Credential cred = account.mHostAuthRecv.mCredential;
495        if (cred != null) {
496            if (cred.isSaved()) {
497                cred.update(context, cred.toContentValues());
498            } else {
499                cred.save(context);
500                account.mHostAuthRecv.mCredentialKey = cred.mId;
501            }
502        }
503        account.mHostAuthRecv.update(context, account.mHostAuthRecv.toContentValues());
504        // Update the backup (side copy) of the accounts
505        AccountBackupRestore.backup(context);
506    }
507
508    /**
509     * Entry point from Activity after entering new settings and verifying them.  For setup mode.
510     */
511    public static void saveSettingsAfterSetup(Context context, SetupDataFragment setupData) {
512        final Account account = setupData.getAccount();
513        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(context);
514        final HostAuth sendAuth = account.getOrCreateHostAuthSend(context);
515
516        // Set the username and password for the outgoing settings to the username and
517        // password the user just set for incoming.  Use the verified host address to try and
518        // pick a smarter outgoing address.
519        final String hostName =
520                AccountSettingsUtils.inferServerName(context, recvAuth.mAddress, null, "smtp");
521        sendAuth.setLogin(recvAuth.mLogin, recvAuth.mPassword);
522        sendAuth.setConnection(sendAuth.mProtocol, hostName, sendAuth.mPort, sendAuth.mFlags);
523    }
524
525    /**
526     * Entry point from Activity, when "next" button is clicked
527     */
528    @Override
529    public void collectUserInput() {
530        final Account account = mSetupData.getAccount();
531
532        // Make sure delete policy is an valid option before using it; otherwise, the results are
533        // indeterminate, I suspect...
534        if (mDeletePolicyView.getVisibility() == View.VISIBLE) {
535            account.setDeletePolicy(
536                    (Integer) ((SpinnerOption) mDeletePolicyView.getSelectedItem()).value);
537        }
538
539        final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext);
540        final String userName = mUsernameView.getText().toString().trim();
541        final String userPassword = mAuthenticationView.getPassword();
542        recvAuth.setLogin(userName, userPassword);
543        if (!TextUtils.isEmpty(mAuthenticationView.getOAuthProvider())) {
544            Credential cred = recvAuth.getOrCreateCredential(getActivity());
545            cred.mProviderId = mAuthenticationView.getOAuthProvider();
546        }
547
548        final String serverAddress = mServerView.getText().toString().trim();
549        int serverPort;
550        try {
551            serverPort = Integer.parseInt(mPortView.getText().toString().trim());
552        } catch (NumberFormatException e) {
553            serverPort = getPortFromSecurityType(getSslSelected());
554            LogUtils.d(LogUtils.TAG, "Non-integer server port; using '" + serverPort + "'");
555        }
556        final int securityType =
557                (Integer) ((SpinnerOption) mSecurityTypeView.getSelectedItem()).value;
558        recvAuth.setConnection(mBaseScheme, serverAddress, serverPort, securityType);
559        if (mServiceInfo.offerPrefix) {
560            final String prefix = mImapPathPrefixView.getText().toString().trim();
561            recvAuth.mDomain = TextUtils.isEmpty(prefix) ? null : ("/" + prefix);
562        } else {
563            recvAuth.mDomain = null;
564        }
565        recvAuth.mClientCertAlias = mClientCertificateSelector.getCertificate();
566
567        final Callback callback = (Callback) getActivity();
568        callback.onAccountServerUIComplete(SetupDataFragment.CHECK_INCOMING);
569    }
570
571    @Override
572    public boolean haveSettingsChanged() {
573        final boolean deletePolicyChanged;
574
575        // Only verify the delete policy if the control is visible (i.e. is a pop3 account)
576        if (mDeletePolicyView != null && mDeletePolicyView.getVisibility() == View.VISIBLE) {
577            int newDeletePolicy =
578                (Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value;
579            deletePolicyChanged = mLoadedDeletePolicy != newDeletePolicy;
580        } else {
581            deletePolicyChanged = false;
582        }
583
584        return deletePolicyChanged || super.haveSettingsChanged();
585    }
586
587    @Override
588    public void onValidateStateChanged() {
589        validateFields();
590    }
591
592    @Override
593    public void onRequestSignIn() {
594        // Launch the credentials activity.
595        final String protocol =
596                mSetupData.getAccount().getOrCreateHostAuthRecv(mAppContext).mProtocol;
597        final Intent intent = AccountCredentials.getAccountCredentialsIntent(getActivity(),
598                mUsernameView.getText().toString(), protocol);
599        startActivityForResult(intent, SIGN_IN_REQUEST);
600    }
601
602    @Override
603    public void onCertificateRequested() {
604        // XXX reimplement
605        final Intent intent = new Intent(CertificateRequestor.ACTION_REQUEST_CERT);
606        intent.setData(Uri.parse("eas://com.android.emailcommon/certrequest"));
607        startActivityForResult(intent, CERTIFICATE_REQUEST);
608    }
609
610    @Override
611    public void onActivityResult(int requestCode, int resultCode, Intent data) {
612        if (requestCode == CERTIFICATE_REQUEST && resultCode == Activity.RESULT_OK) {
613            final String certAlias = data.getStringExtra(CertificateRequestor.RESULT_ALIAS);
614            if (certAlias != null) {
615                mClientCertificateSelector.setCertificate(certAlias);
616            }
617        } else if (requestCode == SIGN_IN_REQUEST && resultCode == Activity.RESULT_OK) {
618            final Account account = mSetupData.getAccount();
619            final HostAuth recvAuth = account.getOrCreateHostAuthRecv(getActivity());
620            AccountSetupCredentialsFragment.populateHostAuthWithResults(mAppContext, recvAuth,
621                    data.getExtras());
622            mAuthenticationView.setAuthInfo(mServiceInfo.offerOAuth, recvAuth);
623        }
624    }
625}
626