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