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