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