AccountSetupBasics.java revision 858c2822777f74947e81476125590ad06bfe4803
1/* 2 * Copyright (C) 2008 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 com.android.email.Email; 20import com.android.email.EmailAddressValidator; 21import com.android.email.R; 22import com.android.email.Utility; 23import com.android.email.VendorPolicyLoader; 24import com.android.email.activity.ActivityHelper; 25import com.android.email.activity.Welcome; 26import com.android.email.activity.setup.AccountSettingsUtils.Provider; 27import com.android.email.provider.EmailContent; 28import com.android.email.provider.EmailContent.Account; 29import com.android.email.provider.EmailContent.HostAuth; 30 31import android.accounts.AccountAuthenticatorResponse; 32import android.accounts.AccountManager; 33import android.app.Activity; 34import android.app.ActivityManager; 35import android.app.AlertDialog; 36import android.app.Dialog; 37import android.app.DialogFragment; 38import android.app.FragmentTransaction; 39import android.content.Context; 40import android.content.DialogInterface; 41import android.content.Intent; 42import android.os.AsyncTask; 43import android.os.Bundle; 44import android.text.Editable; 45import android.text.TextUtils; 46import android.text.TextWatcher; 47import android.util.Log; 48import android.view.View; 49import android.view.View.OnClickListener; 50import android.widget.Button; 51import android.widget.CheckBox; 52import android.widget.EditText; 53import android.widget.TextView; 54import android.widget.Toast; 55 56import java.net.URI; 57import java.net.URISyntaxException; 58import java.util.concurrent.Callable; 59import java.util.concurrent.ExecutionException; 60import java.util.concurrent.FutureTask; 61 62/** 63 * Prompts the user for the email address and password. Also prompts for "Use this account as 64 * default" if this is the 2nd+ account being set up. 65 * 66 * If the domain is well-known, the account is configured fully and checked immediately 67 * using AccountCheckSettingsFragment. If this succeeds we proceed directly to AccountSetupOptions. 68 * 69 * If the domain is not known, or the user selects Manual setup, we invoke the 70 * AccountSetupAccountType activity where the user can begin to manually configure the account. 71 * 72 * === Support for automated testing == 73 * This activity can also be launched directly via ACTION_CREATE_ACCOUNT. This is intended 74 * only for use by continuous test systems, and is currently only available when 75 * {@link ActivityManager#isRunningInTestHarness()} is set. To use this mode, you must construct 76 * an intent which contains all necessary information to create the account. No connection 77 * checking is done, so the account may or may not actually work. Here is a sample command, for a 78 * gmail account "test_account" with a password of "test_password". 79 * 80 * $ adb shell am start -a com.android.email.CREATE_ACCOUNT \ 81 * -e EMAIL test_account@gmail.com \ 82 * -e USER "Test Account Name" \ 83 * -e INCOMING imap+ssl+://test_account:test_password@imap.gmail.com \ 84 * -e OUTGOING smtp+ssl+://test_account:test_password@smtp.gmail.com 85 * 86 * Note: For accounts that require the full email address in the login, encode the @ as %40. 87 * Note: Exchange accounts that require device security policies cannot be created automatically. 88 */ 89public class AccountSetupBasics extends AccountSetupActivity 90 implements OnClickListener, TextWatcher, AccountCheckSettingsFragment.Callbacks { 91 92 private final static boolean ENTER_DEBUG_SCREEN = true; 93 94 /** 95 * Direct access for forcing account creation 96 * For use by continuous automated test system (e.g. in conjunction with monkey tests) 97 */ 98 private final String ACTION_CREATE_ACCOUNT = "com.android.email.CREATE_ACCOUNT"; 99 private final String EXTRA_CREATE_ACCOUNT_EMAIL = "EMAIL"; 100 private final String EXTRA_CREATE_ACCOUNT_USER = "USER"; 101 private final String EXTRA_CREATE_ACCOUNT_INCOMING = "INCOMING"; 102 private final String EXTRA_CREATE_ACCOUNT_OUTGOING = "OUTGOING"; 103 private final Boolean DEBUG_ALLOW_NON_TEST_HARNESS_CREATION = false; 104 105 private final static String STATE_KEY_PROVIDER = "AccountSetupBasics.provider"; 106 107 // NOTE: If you change this value, confirm that the new interval exists in arrays.xml 108 private final static int DEFAULT_ACCOUNT_CHECK_INTERVAL = 15; 109 110 // Support for UI 111 private TextView mWelcomeView; 112 private EditText mEmailView; 113 private EditText mPasswordView; 114 private CheckBox mDefaultView; 115 private EmailAddressValidator mEmailValidator = new EmailAddressValidator(); 116 private Provider mProvider; 117 private Button mManualButton; 118 private Button mNextButton; 119 private boolean mNextButtonInhibit; 120 121 // Used when this Activity is called as part of account authentification flow, 122 // which requires to do extra work before and after the account creation. 123 // See also AccountAuthenticatorActivity. 124 private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null; 125 private Bundle mResultBundle = null; 126 127 // FutureTask to look up the owner 128 FutureTask<String> mOwnerLookupTask; 129 130 public static void actionNewAccount(Activity fromActivity) { 131 SetupData.init(SetupData.FLOW_MODE_NORMAL); 132 fromActivity.startActivity(new Intent(fromActivity, AccountSetupBasics.class)); 133 } 134 135 /** 136 * This generates setup data that can be used to start a self-contained account creation flow 137 * for exchange accounts. 138 */ 139 public static Intent actionSetupExchangeIntent(Context context) { 140 SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS); 141 return new Intent(context, AccountSetupBasics.class); 142 } 143 144 /** 145 * This generates setup data that can be used to start a self-contained account creation flow 146 * for pop/imap accounts. 147 */ 148 public static Intent actionSetupPopImapIntent(Context context) { 149 SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP); 150 return new Intent(context, AccountSetupBasics.class); 151 } 152 153 public static void actionAccountCreateFinishedAccountFlow(Activity fromActivity) { 154 Intent i= new Intent(fromActivity, AccountSetupBasics.class); 155 // If we're in the "account flow" (from AccountManager), we want to return to the caller 156 // (in the settings app) 157 SetupData.init(SetupData.FLOW_MODE_RETURN_TO_CALLER); 158 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 159 fromActivity.startActivity(i); 160 } 161 162 public static void actionAccountCreateFinished(final Activity fromActivity, 163 final long accountId) { 164 Utility.runAsync(new Runnable() { 165 public void run() { 166 Intent i = new Intent(fromActivity, AccountSetupBasics.class); 167 // If we're not in the "account flow" (from AccountManager), we want to show the 168 // message list for the new inbox 169 Account account = Account.restoreAccountWithId(fromActivity, accountId); 170 SetupData.init(SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST, account); 171 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 172 fromActivity.startActivity(i); 173 }}); 174 } 175 176 @Override 177 public void onCreate(Bundle savedInstanceState) { 178 super.onCreate(savedInstanceState); 179 ActivityHelper.debugSetWindowFlags(this); 180 181 // Check for forced account creation first, as it comes from an externally-generated 182 // intent and won't have any SetupData prepared. 183 String action = getIntent().getAction(); 184 if (ACTION_CREATE_ACCOUNT.equals(action)) { 185 SetupData.init(SetupData.FLOW_MODE_FORCE_CREATE); 186 } 187 188 int flowMode = SetupData.getFlowMode(); 189 if (flowMode == SetupData.FLOW_MODE_RETURN_TO_CALLER) { 190 // Return to the caller who initiated account creation 191 finish(); 192 return; 193 } else if (flowMode == SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST) { 194 Account account = SetupData.getAccount(); 195 if (account != null && account.mId >= 0) { 196 // Show the message list for the new account 197 Welcome.actionOpenAccountInbox(this, account.mId); 198 finish(); 199 return; 200 } 201 } 202 203 setContentView(R.layout.account_setup_basics); 204 205 mWelcomeView = (TextView) findViewById(R.id.instructions); 206 mEmailView = (EditText) findViewById(R.id.account_email); 207 mPasswordView = (EditText) findViewById(R.id.account_password); 208 mDefaultView = (CheckBox) findViewById(R.id.account_default); 209 210 mEmailView.addTextChangedListener(this); 211 mPasswordView.addTextChangedListener(this); 212 213 // If there are one or more accounts already in existence, then display 214 // the "use as default" checkbox (it defaults to hidden). 215 new DisplayCheckboxTask().execute(); 216 217 boolean manualButtonDisplayed = true; 218 boolean alternateStrings = false; 219 if (flowMode == SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) { 220 // No need for manual button -> next is appropriate 221 manualButtonDisplayed = false; 222 // Swap welcome text for EAS-specific text 223 alternateStrings = VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings(); 224 setTitle(alternateStrings 225 ? R.string.account_setup_basics_exchange_title_alternate 226 : R.string.account_setup_basics_exchange_title); 227 mWelcomeView.setText(alternateStrings 228 ? R.string.accounts_welcome_exchange_alternate 229 : R.string.accounts_welcome_exchange); 230 } 231 232 // Configure buttons 233 mManualButton = (Button) findViewById(R.id.manual_setup); 234 mNextButton = (Button) findViewById(R.id.next); 235 mManualButton.setVisibility(manualButtonDisplayed ? View.VISIBLE : View.INVISIBLE); 236 mManualButton.setOnClickListener(this); 237 mNextButton.setOnClickListener(this); 238 // Force disabled until validator notifies otherwise 239 onEnableProceedButtons(false); 240 // Lightweight debounce while Async tasks underway 241 mNextButtonInhibit = false; 242 243 mAccountAuthenticatorResponse = 244 getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE); 245 246 if (mAccountAuthenticatorResponse != null) { 247 mAccountAuthenticatorResponse.onRequestContinued(); 248 } 249 250 // Load fields, but only once 251 String userName = SetupData.getUsername(); 252 if (userName != null) { 253 mEmailView.setText(userName); 254 SetupData.setUsername(null); 255 } 256 String password = SetupData.getPassword(); 257 if (userName != null) { 258 mPasswordView.setText(password); 259 SetupData.setPassword(null); 260 } 261 262 // Handle force account creation immediately (now that fragment is set up) 263 // This is never allowed in a normal user build and will exit immediately. 264 if (SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) { 265 if (!DEBUG_ALLOW_NON_TEST_HARNESS_CREATION && 266 !ActivityManager.isRunningInTestHarness()) { 267 Log.e(Email.LOG_TAG, 268 "ERROR: Force account create only allowed while in test harness"); 269 finish(); 270 return; 271 } 272 Intent intent = getIntent(); 273 String email = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_EMAIL); 274 String user = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_USER); 275 String incoming = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_INCOMING); 276 String outgoing = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_OUTGOING); 277 if (TextUtils.isEmpty(email) || TextUtils.isEmpty(user) || 278 TextUtils.isEmpty(incoming) || TextUtils.isEmpty(outgoing)) { 279 Log.e(Email.LOG_TAG, "ERROR: Force account create requires extras EMAIL, USER, " + 280 "INCOMING, OUTGOING"); 281 finish(); 282 return; 283 } 284 forceCreateAccount(email, user, incoming, outgoing); 285 onCheckSettingsComplete(AccountCheckSettingsFragment.CHECK_SETTINGS_OK); // calls finish 286 return; 287 } 288 289 if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { 290 mProvider = (Provider) savedInstanceState.getSerializable(STATE_KEY_PROVIDER); 291 } 292 293 // Launch a worker to look up the owner name. It should be ready well in advance of 294 // the time the user clicks next or manual. 295 mOwnerLookupTask = new FutureTask<String>(mOwnerLookupCallable); 296 Utility.runAsync(mOwnerLookupTask); 297 } 298 299 @Override 300 public void finish() { 301 if (mAccountAuthenticatorResponse != null) { 302 // send the result bundle back if set, otherwise send an error. 303 if (mResultBundle != null) { 304 mAccountAuthenticatorResponse.onResult(mResultBundle); 305 } else { 306 mAccountAuthenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED, 307 "canceled"); 308 } 309 mAccountAuthenticatorResponse = null; 310 } 311 super.finish(); 312 } 313 314 @Override 315 public void onSaveInstanceState(Bundle outState) { 316 super.onSaveInstanceState(outState); 317 if (mProvider != null) { 318 outState.putSerializable(STATE_KEY_PROVIDER, mProvider); 319 } 320 } 321 322 /** 323 * Implements OnClickListener 324 */ 325 @Override 326 public void onClick(View v) { 327 switch (v.getId()) { 328 case R.id.next: 329 // Simple debounce - just ignore while async checks are underway 330 if (mNextButtonInhibit) { 331 return; 332 } 333 onNext(); 334 break; 335 case R.id.manual_setup: 336 onManualSetup(false); 337 break; 338 } 339 } 340 341 /** 342 * Implements TextWatcher 343 */ 344 public void afterTextChanged(Editable s) { 345 validateFields(); 346 } 347 348 /** 349 * Implements TextWatcher 350 */ 351 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 352 } 353 354 /** 355 * Implements TextWatcher 356 */ 357 public void onTextChanged(CharSequence s, int start, int before, int count) { 358 } 359 360 private void validateFields() { 361 boolean valid = Utility.isTextViewNotEmpty(mEmailView) 362 && Utility.isTextViewNotEmpty(mPasswordView) 363 && mEmailValidator.isValid(mEmailView.getText().toString().trim()); 364 onEnableProceedButtons(valid); 365 366 // Warn (but don't prevent) if password has leading/trailing spaces 367 AccountSettingsUtils.checkPasswordSpaces(this, mPasswordView); 368 } 369 370 /** 371 * Return an existing username if found, or null. This is the result of the Callable (below). 372 */ 373 private String getOwnerName() { 374 String result = null; 375 try { 376 result = mOwnerLookupTask.get(); 377 } catch (InterruptedException e) { 378 } catch (ExecutionException e) { 379 } 380 return result; 381 } 382 383 /** 384 * Callable that returns the username (based on other accounts) or null. 385 */ 386 private Callable<String> mOwnerLookupCallable = new Callable<String>() { 387 public String call() { 388 Context context = AccountSetupBasics.this; 389 String name = null; 390 long defaultId = Account.getDefaultAccountId(context); 391 if (defaultId != -1) { 392 Account account = Account.restoreAccountWithId(context, defaultId); 393 if (account != null) { 394 name = account.getSenderName(); 395 } 396 } 397 return name; 398 } 399 }; 400 401 /** 402 * Finish the auto setup process, in some cases after showing a warning dialog. 403 */ 404 private void finishAutoSetup() { 405 String email = mEmailView.getText().toString().trim(); 406 String password = mPasswordView.getText().toString(); 407 String[] emailParts = email.split("@"); 408 String user = emailParts[0]; 409 String domain = emailParts[1]; 410 URI incomingUri = null; 411 URI outgoingUri = null; 412 String incomingUsername = mProvider.incomingUsernameTemplate; 413 try { 414 incomingUsername = incomingUsername.replaceAll("\\$email", email); 415 incomingUsername = incomingUsername.replaceAll("\\$user", user); 416 incomingUsername = incomingUsername.replaceAll("\\$domain", domain); 417 418 URI incomingUriTemplate = mProvider.incomingUriTemplate; 419 incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":" 420 + password, incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), 421 incomingUriTemplate.getPath(), null, null); 422 423 String outgoingUsername = mProvider.outgoingUsernameTemplate; 424 outgoingUsername = outgoingUsername.replaceAll("\\$email", email); 425 outgoingUsername = outgoingUsername.replaceAll("\\$user", user); 426 outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain); 427 428 URI outgoingUriTemplate = mProvider.outgoingUriTemplate; 429 outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":" 430 + password, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), 431 outgoingUriTemplate.getPath(), null, null); 432 433 } catch (URISyntaxException use) { 434 /* 435 * If there is some problem with the URI we give up and go on to 436 * manual setup. Technically speaking, AutoDiscover is OK here, since user clicked 437 * "Next" to get here. This would never happen in practice because we don't expect 438 * to find any EAS accounts in the providers list. 439 */ 440 onManualSetup(true); 441 return; 442 } 443 444 // Populate the setup data, assuming that the duplicate account check will succeed 445 populateSetupData(getOwnerName(), email, mDefaultView.isChecked(), 446 incomingUri.toString(), outgoingUri.toString()); 447 448 // Stop here if the login credentials duplicate an existing account 449 // Launch an Async task to do the work 450 new DuplicateCheckTask(this, incomingUri.getHost(), incomingUsername).execute(); 451 } 452 453 /** 454 * Async task that continues the work of finishAutoSetup(). Checks for a duplicate 455 * account and then either alerts the user, or continues. 456 */ 457 private class DuplicateCheckTask extends AsyncTask<Void, Void, Account> { 458 private final Context mContext; 459 private final String mCheckHost; 460 private final String mCheckLogin; 461 462 public DuplicateCheckTask(Context context, String checkHost, String checkLogin) { 463 mContext = context; 464 mCheckHost = checkHost; 465 mCheckLogin = checkLogin; 466 // Prevent additional clicks on the next button during Async lookup 467 mNextButtonInhibit = true; 468 } 469 470 @Override 471 protected Account doInBackground(Void... params) { 472 EmailContent.Account account = Utility.findExistingAccount(mContext, -1, 473 mCheckHost, mCheckLogin); 474 return account; 475 } 476 477 @Override 478 protected void onPostExecute(Account duplicateAccount) { 479 mNextButtonInhibit = false; 480 // Show duplicate account warning, or proceed 481 if (duplicateAccount != null) { 482 DuplicateAccountDialogFragment dialogFragment = 483 DuplicateAccountDialogFragment.newInstance(duplicateAccount.mDisplayName); 484 dialogFragment.show(getFragmentManager(), DuplicateAccountDialogFragment.TAG); 485 return; 486 } else { 487 AccountCheckSettingsFragment checkerFragment = 488 AccountCheckSettingsFragment.newInstance( 489 SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING, null); 490 FragmentTransaction transaction = getFragmentManager().beginTransaction(); 491 transaction.add(checkerFragment, AccountCheckSettingsFragment.TAG); 492 transaction.addToBackStack("back"); 493 transaction.commit(); 494 } 495 } 496 } 497 498 499 /** 500 * When "next" button is clicked 501 */ 502 private void onNext() { 503 // Try auto-configuration from XML providers (unless in EAS mode, we can skip it) 504 if (SetupData.getFlowMode() != SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) { 505 String email = mEmailView.getText().toString().trim(); 506 String[] emailParts = email.split("@"); 507 String domain = emailParts[1].trim(); 508 mProvider = AccountSettingsUtils.findProviderForDomain(this, domain); 509 if (mProvider != null) { 510 if (mProvider.note != null) { 511 NoteDialogFragment dialogFragment = 512 NoteDialogFragment.newInstance(mProvider.note); 513 dialogFragment.show(getFragmentManager(), NoteDialogFragment.TAG); 514 } else { 515 finishAutoSetup(); 516 } 517 return; 518 } 519 } 520 // Can't use auto setup (although EAS accounts may still be able to AutoDiscover) 521 onManualSetup(true); 522 } 523 524 /** 525 * When "manual setup" button is clicked 526 * 527 * @param allowAutoDiscover - true if the user clicked 'next' and (if the account is EAS) 528 * it's OK to use autodiscover. false to prevent autodiscover and go straight to manual setup. 529 * Ignored for IMAP & POP accounts. 530 */ 531 private void onManualSetup(boolean allowAutoDiscover) { 532 String email = mEmailView.getText().toString().trim(); 533 String password = mPasswordView.getText().toString(); 534 String[] emailParts = email.split("@"); 535 String user = emailParts[0].trim(); 536 String domain = emailParts[1].trim(); 537 538 // Alternate entry to the debug options screen (for devices without a physical keyboard: 539 // Username: d@d.d 540 // Password: debug 541 if (ENTER_DEBUG_SCREEN && "d@d.d".equals(email) && "debug".equals(password)) { 542 mEmailView.setText(""); 543 mPasswordView.setText(""); 544 AccountSettingsXL.actionSettingsWithDebug(this); 545 return; 546 } 547 548 String uriString = null; 549 try { 550 URI uri = new URI("placeholder", user + ":" + password, domain, -1, null, null, null); 551 uriString = uri.toString(); 552 } catch (URISyntaxException use) { 553 // If we can't set up the URL, don't continue - account setup pages will fail too 554 Toast.makeText(this, R.string.account_setup_username_password_toast, 555 Toast.LENGTH_LONG).show(); 556 return; 557 } 558 559 populateSetupData(getOwnerName(), email, mDefaultView.isChecked(), uriString, uriString); 560 561 SetupData.setAllowAutodiscover(allowAutoDiscover); 562 AccountSetupAccountType.actionSelectAccountType(this); 563 } 564 565 /** 566 * To support continuous testing, we allow the forced creation of accounts. 567 * This works in a manner fairly similar to automatic setup, in which the complete server 568 * Uri's are available, except that we will also skip checking (as if both checks were true) 569 * and all other UI. 570 * 571 * @param email The email address for the new account 572 * @param user The user name for the new account 573 * @param incoming The URI-style string defining the incoming account 574 * @param outgoing The URI-style string defining the outgoing account 575 */ 576 private void forceCreateAccount(String email, String user, String incoming, String outgoing) { 577 populateSetupData(user, email, false, incoming, outgoing); 578 } 579 580 /** 581 * Populate SetupData's account with complete setup info. 582 */ 583 private void populateSetupData(String senderName, String senderEmail, boolean isDefault, 584 String incoming, String outgoing) { 585 Account account = SetupData.getAccount(); 586 account.setSenderName(senderName); 587 account.setEmailAddress(senderEmail); 588 account.setDisplayName(senderEmail); 589 account.setDefaultAccount(isDefault); 590 SetupData.setDefault(isDefault); // TODO - why duplicated, if already set in account 591 account.setStoreUri(this, incoming); 592 account.setSenderUri(this, outgoing); 593 594 // Set sync and delete policies for specific account types 595 if (incoming.startsWith("imap")) { 596 // Delete policy must be set explicitly, because IMAP does not provide a UI selection 597 // for it. This logic needs to be followed in the auto setup flow as well. 598 account.setDeletePolicy(EmailContent.Account.DELETE_POLICY_ON_DELETE); 599 } 600 601 if (incoming.startsWith("eas")) { 602 account.setSyncInterval(Account.CHECK_INTERVAL_PUSH); 603 } else { 604 account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL); 605 } 606 } 607 608 /** 609 * Implements AccountCheckSettingsFragment.Callbacks 610 * 611 * This is used in automatic setup mode to jump directly down to the options screen. 612 */ 613 @Override 614 public void onCheckSettingsComplete(int result) { 615 if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) { 616 AccountSetupOptions.actionOptions(this); 617 finish(); 618 } 619 } 620 621 /** 622 * Implements AccountCheckSettingsFragment.Callbacks 623 * This is overridden only by AccountSetupExchange 624 */ 625 @Override 626 public void onAutoDiscoverComplete(int result, HostAuth hostAuth) { 627 throw new IllegalStateException(); 628 } 629 630 /** 631 * AsyncTask checks count of accounts and displays "use this account as default" checkbox 632 * if there are more than one. 633 */ 634 private class DisplayCheckboxTask extends AsyncTask<Void, Void, Integer> { 635 636 @Override 637 protected Integer doInBackground(Void... params) { 638 return EmailContent.count(AccountSetupBasics.this, EmailContent.Account.CONTENT_URI); 639 } 640 641 @Override 642 protected void onPostExecute(Integer numAccounts) { 643 if (numAccounts > 0) { 644 Activity activity = AccountSetupBasics.this; 645 activity.findViewById(R.id.account_default_divider_1).setVisibility(View.VISIBLE); 646 mDefaultView.setVisibility(View.VISIBLE); 647 activity.findViewById(R.id.account_default_divider_2).setVisibility(View.VISIBLE); 648 } 649 } 650 } 651 652 private void onEnableProceedButtons(boolean enabled) { 653 mManualButton.setEnabled(enabled); 654 mNextButton.setEnabled(enabled); 655 } 656 657 /** 658 * Dialog fragment to show "setup note" dialog 659 */ 660 public static class NoteDialogFragment extends DialogFragment { 661 private final static String TAG = "NoteDialogFragment"; 662 663 // Argument bundle keys 664 private final static String BUNDLE_KEY_NOTE = "NoteDialogFragment.Note"; 665 666 /** 667 * Create the dialog with parameters 668 */ 669 public static NoteDialogFragment newInstance(String note) { 670 NoteDialogFragment f = new NoteDialogFragment(); 671 Bundle b = new Bundle(); 672 b.putString(BUNDLE_KEY_NOTE, note); 673 f.setArguments(b); 674 return f; 675 } 676 677 @Override 678 public Dialog onCreateDialog(Bundle savedInstanceState) { 679 Context context = getActivity(); 680 final String note = getArguments().getString(BUNDLE_KEY_NOTE); 681 682 return new AlertDialog.Builder(context) 683 .setIconAttribute(android.R.attr.alertDialogIcon) 684 .setTitle(android.R.string.dialog_alert_title) 685 .setMessage(note) 686 .setPositiveButton( 687 R.string.okay_action, 688 new DialogInterface.OnClickListener() { 689 public void onClick(DialogInterface dialog, int which) { 690 Activity a = getActivity(); 691 if (a instanceof AccountSetupBasics) { 692 ((AccountSetupBasics)a).finishAutoSetup(); 693 } 694 dismiss(); 695 } 696 }) 697 .setNegativeButton( 698 context.getString(R.string.cancel_action), 699 null) 700 .create(); 701 } 702 } 703} 704