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