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