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