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 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 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 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 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 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 261 /** 262 * Called when the fragment is visible to the user and actively running. 263 */ 264 @Override 265 public void onResume() { 266 super.onResume(); 267 validateFields(); 268 } 269 270 @Override 271 public void onDestroyView() { 272 // Make sure we don't get callbacks after the views are supposed to be destroyed 273 // and also don't hold onto them longer than we need 274 if (mUsernameView != null) { 275 mUsernameView.removeTextChangedListener(mValidationTextWatcher); 276 } 277 mUsernameView = null; 278 mServerLabelView = null; 279 if (mServerView != null) { 280 mServerView.removeTextChangedListener(mValidationTextWatcher); 281 } 282 mServerView = null; 283 if (mPortView != null) { 284 mPortView.removeTextChangedListener(mValidationTextWatcher); 285 } 286 mPortView = null; 287 if (mSecurityTypeView != null) { 288 mSecurityTypeView.setOnItemSelectedListener(null); 289 } 290 mSecurityTypeView = null; 291 mDeletePolicyLabelView = null; 292 mDeletePolicyView = null; 293 mImapPathPrefixSectionView = null; 294 mImapPathPrefixView = null; 295 mDeviceIdSection = null; 296 mClientCertificateSelector = null; 297 298 super.onDestroyView(); 299 } 300 301 @Override 302 public void onSaveInstanceState(Bundle outState) { 303 super.onSaveInstanceState(outState); 304 305 outState.putString(STATE_KEY_CREDENTIAL, mCacheLoginCredential); 306 outState.putBoolean(STATE_KEY_LOADED, mLoaded); 307 } 308 309 /** 310 * Configure the editor for the account type 311 */ 312 private void configureEditor() { 313 final Account account = mSetupData.getAccount(); 314 if (account == null || account.mHostAuthRecv == null) { 315 LogUtils.e(LogUtils.TAG, 316 "null account or host auth. account null: %b host auth null: %b", 317 account == null, account == null || account.mHostAuthRecv == null); 318 return; 319 } 320 mBaseScheme = account.mHostAuthRecv.mProtocol; 321 mServerLabelView.setText(R.string.account_setup_incoming_server_label); 322 mServerView.setContentDescription(getResources().getText( 323 R.string.account_setup_incoming_server_label)); 324 if (!mServiceInfo.offerPrefix) { 325 mImapPathPrefixSectionView.setVisibility(View.GONE); 326 } 327 if (!mServiceInfo.offerLocalDeletes) { 328 mDeletePolicyLabelView.setVisibility(View.GONE); 329 mDeletePolicyView.setVisibility(View.GONE); 330 mPortView.setImeOptions(EditorInfo.IME_ACTION_NEXT); 331 } 332 } 333 334 /** 335 * Load the current settings into the UI 336 */ 337 private void loadSettings() { 338 if (mLoaded) return; 339 340 final Account account = mSetupData.getAccount(); 341 final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext); 342 mServiceInfo = mSetupData.getIncomingServiceInfo(getActivity()); 343 final List<VendorPolicyLoader.OAuthProvider> oauthProviders = 344 AccountSettingsUtils.getAllOAuthProviders(getActivity()); 345 final boolean offerOAuth = (mServiceInfo.offerOAuth && oauthProviders.size() > 0); 346 347 mAuthenticationView.setAuthInfo(offerOAuth, recvAuth); 348 if (mAuthenticationLabel != null) { 349 if (offerOAuth) { 350 mAuthenticationLabel.setText(R.string.authentication_label); 351 } else { 352 mAuthenticationLabel.setText(R.string.account_setup_basics_password_label); 353 } 354 } 355 356 final String username = recvAuth.mLogin; 357 if (username != null) { 358 //*** For eas? 359 // Add a backslash to the start of the username, but only if the username has no 360 // backslash in it. 361 //if (userName.indexOf('\\') < 0) { 362 // userName = "\\" + userName; 363 //} 364 mUsernameView.setText(username); 365 } 366 367 if (mServiceInfo.offerPrefix) { 368 final String prefix = recvAuth.mDomain; 369 if (prefix != null && prefix.length() > 0) { 370 mImapPathPrefixView.setText(prefix.substring(1)); 371 } 372 } 373 374 // The delete policy is set for all legacy accounts. For POP3 accounts, the user sets 375 // the policy explicitly. For IMAP accounts, the policy is set when the Account object 376 // is created. @see AccountSetupBasics#populateSetupData 377 mLoadedDeletePolicy = account.getDeletePolicy(); 378 SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy); 379 380 int flags = recvAuth.mFlags; 381 if (mServiceInfo.defaultSsl) { 382 flags |= HostAuth.FLAG_SSL; 383 } 384 // Strip out any flags that are not related to security type. 385 int securityTypeFlags = (flags & HostAuth.FLAG_TRANSPORTSECURITY_MASK); 386 SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, securityTypeFlags); 387 388 final String hostname = recvAuth.mAddress; 389 if (hostname != null) { 390 mServerView.setText(hostname); 391 } 392 393 final int port = recvAuth.mPort; 394 if (port != HostAuth.PORT_UNKNOWN) { 395 mPortView.setText(Integer.toString(port)); 396 } else { 397 updatePortFromSecurityType(); 398 } 399 400 if (!TextUtils.isEmpty(recvAuth.mClientCertAlias)) { 401 mClientCertificateSelector.setCertificate(recvAuth.mClientCertAlias); 402 } 403 404 // Make a deep copy of the HostAuth to compare with later 405 final Parcel parcel = Parcel.obtain(); 406 parcel.writeParcelable(recvAuth, recvAuth.describeContents()); 407 parcel.setDataPosition(0); 408 mLoadedRecvAuth = parcel.readParcelable(HostAuth.class.getClassLoader()); 409 parcel.recycle(); 410 411 mLoaded = true; 412 validateFields(); 413 } 414 415 /** 416 * Check the values in the fields and decide if it makes sense to enable the "next" button 417 */ 418 private void validateFields() { 419 if (!mLoaded) return; 420 enableNextButton(!TextUtils.isEmpty(mUsernameView.getText()) 421 && mAuthenticationView.getAuthValid() 422 && Utility.isServerNameValid(mServerView) 423 && Utility.isPortFieldValid(mPortView)); 424 425 mCacheLoginCredential = mUsernameView.getText().toString().trim(); 426 } 427 428 private int getPortFromSecurityType(boolean useSsl) { 429 return useSsl ? mServiceInfo.portSsl : mServiceInfo.port; 430 } 431 432 private boolean getSslSelected() { 433 final int securityType = 434 (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; 435 return ((securityType & HostAuth.FLAG_SSL) != 0); 436 } 437 438 public void onUseSslChanged(boolean useSsl) { 439 if (mServiceInfo.offerCerts) { 440 final int mode = useSsl ? View.VISIBLE : View.GONE; 441 mClientCertificateSelector.setVisibility(mode); 442 String deviceId = ""; 443 try { 444 deviceId = Device.getDeviceId(mAppContext); 445 } catch (IOException e) { 446 // Not required 447 } 448 ((TextView) UiUtilities.getView(getView(), R.id.device_id)).setText(deviceId); 449 450 mDeviceIdSection.setVisibility(mode); 451 } 452 } 453 454 private void updatePortFromSecurityType() { 455 final boolean sslSelected = getSslSelected(); 456 final int port = getPortFromSecurityType(sslSelected); 457 mPortView.setText(Integer.toString(port)); 458 onUseSslChanged(sslSelected); 459 } 460 461 @Override 462 public void saveSettings() { 463 // Reset this here so we don't get stuck on this screen 464 mLoadedDeletePolicy = mSetupData.getAccount().getDeletePolicy(); 465 super.saveSettings(); 466 } 467 468 private static class SaveSettingsLoader extends MailAsyncTaskLoader<Boolean> { 469 private final SetupDataFragment mSetupData; 470 private final boolean mSettingsMode; 471 472 private SaveSettingsLoader(Context context, SetupDataFragment setupData, 473 boolean settingsMode) { 474 super(context); 475 mSetupData = setupData; 476 mSettingsMode = settingsMode; 477 } 478 479 @Override 480 public Boolean loadInBackground() { 481 if (mSettingsMode) { 482 saveSettingsAfterEdit(getContext(), mSetupData); 483 } else { 484 saveSettingsAfterSetup(getContext(), mSetupData); 485 } 486 return true; 487 } 488 489 @Override 490 protected void onDiscardResult(Boolean result) {} 491 } 492 493 @Override 494 public Loader<Boolean> getSaveSettingsLoader() { 495 return new SaveSettingsLoader(mAppContext, mSetupData, mSettingsMode); 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 public static void saveSettingsAfterEdit(Context context, SetupDataFragment setupData) { 505 final Account account = setupData.getAccount(); 506 account.update(context, account.toContentValues()); 507 final Credential cred = account.mHostAuthRecv.mCredential; 508 if (cred != null) { 509 if (cred.isSaved()) { 510 cred.update(context, cred.toContentValues()); 511 } else { 512 cred.save(context); 513 account.mHostAuthRecv.mCredentialKey = cred.mId; 514 } 515 } 516 account.mHostAuthRecv.update(context, account.mHostAuthRecv.toContentValues()); 517 // Update the backup (side copy) of the accounts 518 AccountBackupRestore.backup(context); 519 } 520 521 /** 522 * Entry point from Activity after entering new settings and verifying them. For setup mode. 523 */ 524 public static void saveSettingsAfterSetup(Context context, SetupDataFragment setupData) { 525 final Account account = setupData.getAccount(); 526 final HostAuth recvAuth = account.getOrCreateHostAuthRecv(context); 527 final HostAuth sendAuth = account.getOrCreateHostAuthSend(context); 528 529 // Set the username and password for the outgoing settings to the username and 530 // password the user just set for incoming. Use the verified host address to try and 531 // pick a smarter outgoing address. 532 final String hostName = 533 AccountSettingsUtils.inferServerName(context, recvAuth.mAddress, null, "smtp"); 534 sendAuth.setLogin(recvAuth.mLogin, recvAuth.mPassword); 535 sendAuth.setConnection(sendAuth.mProtocol, hostName, sendAuth.mPort, sendAuth.mFlags); 536 } 537 538 /** 539 * Entry point from Activity, when "next" button is clicked 540 */ 541 @Override 542 public int collectUserInputInternal() { 543 final Account account = mSetupData.getAccount(); 544 545 // Make sure delete policy is an valid option before using it; otherwise, the results are 546 // indeterminate, I suspect... 547 if (mDeletePolicyView.getVisibility() == View.VISIBLE) { 548 account.setDeletePolicy( 549 (Integer) ((SpinnerOption) mDeletePolicyView.getSelectedItem()).value); 550 } 551 552 final HostAuth recvAuth = account.getOrCreateHostAuthRecv(mAppContext); 553 final String userName = mUsernameView.getText().toString().trim(); 554 final String userPassword = mAuthenticationView.getPassword(); 555 recvAuth.setLogin(userName, userPassword); 556 if (!TextUtils.isEmpty(mAuthenticationView.getOAuthProvider())) { 557 Credential cred = recvAuth.getOrCreateCredential(getActivity()); 558 cred.mProviderId = mAuthenticationView.getOAuthProvider(); 559 } 560 561 final String serverAddress = mServerView.getText().toString().trim(); 562 int serverPort; 563 try { 564 serverPort = Integer.parseInt(mPortView.getText().toString().trim()); 565 } catch (NumberFormatException e) { 566 serverPort = getPortFromSecurityType(getSslSelected()); 567 LogUtils.d(LogUtils.TAG, "Non-integer server port; using '" + serverPort + "'"); 568 } 569 final int securityType = 570 (Integer) ((SpinnerOption) mSecurityTypeView.getSelectedItem()).value; 571 recvAuth.setConnection(mBaseScheme, serverAddress, serverPort, securityType); 572 if (mServiceInfo.offerPrefix) { 573 final String prefix = mImapPathPrefixView.getText().toString().trim(); 574 recvAuth.mDomain = TextUtils.isEmpty(prefix) ? null : ("/" + prefix); 575 } else { 576 recvAuth.mDomain = null; 577 } 578 recvAuth.mClientCertAlias = mClientCertificateSelector.getCertificate(); 579 580 return SetupDataFragment.CHECK_INCOMING; 581 } 582 583 @Override 584 public boolean haveSettingsChanged() { 585 final boolean deletePolicyChanged; 586 587 // Only verify the delete policy if the control is visible (i.e. is a pop3 account) 588 if (mDeletePolicyView != null && mDeletePolicyView.getVisibility() == View.VISIBLE) { 589 int newDeletePolicy = 590 (Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value; 591 deletePolicyChanged = mLoadedDeletePolicy != newDeletePolicy; 592 } else { 593 deletePolicyChanged = false; 594 } 595 596 return deletePolicyChanged || super.haveSettingsChanged(); 597 } 598 599 @Override 600 public void onValidateStateChanged() { 601 validateFields(); 602 } 603 604 @Override 605 public void onRequestSignIn() { 606 // Launch the credentials activity. 607 final String protocol = 608 mSetupData.getAccount().getOrCreateHostAuthRecv(mAppContext).mProtocol; 609 final Intent intent = AccountCredentials.getAccountCredentialsIntent(getActivity(), 610 mUsernameView.getText().toString(), protocol); 611 startActivityForResult(intent, SIGN_IN_REQUEST); 612 } 613 614 @Override 615 public void onCertificateRequested() { 616 final Intent intent = new Intent(getString(R.string.intent_exchange_cert_action)); 617 intent.setData(CertificateRequestor.CERTIFICATE_REQUEST_URI); 618 intent.putExtra(CertificateRequestor.EXTRA_HOST, mServerView.getText().toString().trim()); 619 try { 620 intent.putExtra(CertificateRequestor.EXTRA_PORT, 621 Integer.parseInt(mPortView.getText().toString().trim())); 622 } catch (final NumberFormatException e) { 623 LogUtils.d(LogUtils.TAG, "Couldn't parse port %s", mPortView.getText()); 624 } 625 startActivityForResult(intent, CERTIFICATE_REQUEST); 626 } 627 628 @Override 629 public void onActivityResult(int requestCode, int resultCode, Intent data) { 630 if (requestCode == CERTIFICATE_REQUEST && resultCode == Activity.RESULT_OK) { 631 final String certAlias = data.getStringExtra(CertificateRequestor.RESULT_ALIAS); 632 if (certAlias != null) { 633 mClientCertificateSelector.setCertificate(certAlias); 634 } 635 } else if (requestCode == SIGN_IN_REQUEST && resultCode == Activity.RESULT_OK) { 636 final Account account = mSetupData.getAccount(); 637 final HostAuth recvAuth = account.getOrCreateHostAuthRecv(getActivity()); 638 AccountSetupCredentialsFragment.populateHostAuthWithResults(mAppContext, recvAuth, 639 data.getExtras()); 640 mAuthenticationView.setAuthInfo(mServiceInfo.offerOAuth, recvAuth); 641 } 642 } 643 } 644