AccountSetupBasics.java revision 040ddf60cfef4aaecf4bfe1f897fce3248d777a4
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.EmailAddressValidator; 20import com.android.email.R; 21import com.android.email.VendorPolicyLoader; 22import com.android.email.activity.ActivityHelper; 23import com.android.email.activity.Welcome; 24import com.android.email.activity.setup.AccountSettingsUtils.Provider; 25import com.android.email.mail.Store; 26import com.android.emailcommon.Logging; 27import com.android.emailcommon.provider.EmailContent; 28import com.android.emailcommon.provider.EmailContent.Account; 29import com.android.emailcommon.provider.EmailContent.HostAuth; 30import com.android.emailcommon.utility.Utility; 31 32import android.accounts.AccountAuthenticatorResponse; 33import android.accounts.AccountManager; 34import android.app.Activity; 35import android.app.ActivityManager; 36import android.app.AlertDialog; 37import android.app.Dialog; 38import android.app.DialogFragment; 39import android.app.FragmentTransaction; 40import android.content.Context; 41import android.content.DialogInterface; 42import android.content.Intent; 43import android.os.AsyncTask; 44import android.os.Bundle; 45import android.text.Editable; 46import android.text.TextUtils; 47import android.text.TextWatcher; 48import android.util.Log; 49import android.view.View; 50import android.view.View.OnClickListener; 51import android.widget.Button; 52import android.widget.CheckBox; 53import android.widget.EditText; 54import android.widget.TextView; 55import android.widget.Toast; 56 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(Logging.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(Logging.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 425 try { 426 String incomingUsername = mProvider.incomingUsernameTemplate; 427 incomingUsername = incomingUsername.replaceAll("\\$email", email); 428 incomingUsername = incomingUsername.replaceAll("\\$user", user); 429 incomingUsername = incomingUsername.replaceAll("\\$domain", domain); 430 431 Account account = SetupData.getAccount(); 432 HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); 433 Utility.setHostAuthFromString(recvAuth, mProvider.incomingUriTemplate); 434 435 String outgoingUsername = mProvider.outgoingUsernameTemplate; 436 outgoingUsername = outgoingUsername.replaceAll("\\$email", email); 437 outgoingUsername = outgoingUsername.replaceAll("\\$user", user); 438 outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain); 439 440 HostAuth sendAuth = account.getOrCreateHostAuthSend(this); 441 Utility.setHostAuthFromString(sendAuth, mProvider.outgoingUriTemplate); 442 443 // Populate the setup data, assuming that the duplicate account check will succeed 444 populateSetupData(getOwnerName(), email, mDefaultView.isChecked()); 445 446 // Stop here if the login credentials duplicate an existing account 447 // Launch an Async task to do the work 448 new DuplicateCheckTask(this, recvAuth.mAddress, incomingUsername).execute(); 449 } catch (URISyntaxException e) { 450 /* 451 * If there is some problem with the URI we give up and go on to manual setup. 452 * Technically speaking, AutoDiscover is OK here, since the user clicked "Next" 453 * to get here. This will not happen in practice because we don't expect to 454 * find any EAS accounts in the providers list. 455 */ 456 onManualSetup(true); 457 } 458 } 459 460 /** 461 * Async task that continues the work of finishAutoSetup(). Checks for a duplicate 462 * account and then either alerts the user, or continues. 463 */ 464 private class DuplicateCheckTask extends AsyncTask<Void, Void, Account> { 465 private final Context mContext; 466 private final String mCheckHost; 467 private final String mCheckLogin; 468 469 public DuplicateCheckTask(Context context, String checkHost, String checkLogin) { 470 mContext = context; 471 mCheckHost = checkHost; 472 mCheckLogin = checkLogin; 473 // Prevent additional clicks on the next button during Async lookup 474 mNextButtonInhibit = true; 475 } 476 477 @Override 478 protected Account doInBackground(Void... params) { 479 EmailContent.Account account = Utility.findExistingAccount(mContext, -1, 480 mCheckHost, mCheckLogin); 481 return account; 482 } 483 484 @Override 485 protected void onPostExecute(Account duplicateAccount) { 486 mNextButtonInhibit = false; 487 // Exit immediately if the user left before we finished 488 if (mPaused) return; 489 // Show duplicate account warning, or proceed 490 if (duplicateAccount != null) { 491 DuplicateAccountDialogFragment dialogFragment = 492 DuplicateAccountDialogFragment.newInstance(duplicateAccount.mDisplayName); 493 dialogFragment.show(getFragmentManager(), DuplicateAccountDialogFragment.TAG); 494 return; 495 } else { 496 AccountCheckSettingsFragment checkerFragment = 497 AccountCheckSettingsFragment.newInstance( 498 SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING, null); 499 FragmentTransaction transaction = getFragmentManager().beginTransaction(); 500 transaction.add(checkerFragment, AccountCheckSettingsFragment.TAG); 501 transaction.addToBackStack("back"); 502 transaction.commit(); 503 } 504 } 505 } 506 507 508 /** 509 * When "next" button is clicked 510 */ 511 private void onNext() { 512 // Try auto-configuration from XML providers (unless in EAS mode, we can skip it) 513 if (SetupData.getFlowMode() != SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) { 514 String email = mEmailView.getText().toString().trim(); 515 String[] emailParts = email.split("@"); 516 String domain = emailParts[1].trim(); 517 mProvider = AccountSettingsUtils.findProviderForDomain(this, domain); 518 if (mProvider != null) { 519 if (mProvider.note != null) { 520 NoteDialogFragment dialogFragment = 521 NoteDialogFragment.newInstance(mProvider.note); 522 dialogFragment.show(getFragmentManager(), NoteDialogFragment.TAG); 523 } else { 524 finishAutoSetup(); 525 } 526 return; 527 } 528 } 529 // Can't use auto setup (although EAS accounts may still be able to AutoDiscover) 530 onManualSetup(true); 531 } 532 533 /** 534 * When "manual setup" button is clicked 535 * 536 * @param allowAutoDiscover - true if the user clicked 'next' and (if the account is EAS) 537 * it's OK to use autodiscover. false to prevent autodiscover and go straight to manual setup. 538 * Ignored for IMAP & POP accounts. 539 */ 540 private void onManualSetup(boolean allowAutoDiscover) { 541 String email = mEmailView.getText().toString().trim(); 542 String password = mPasswordView.getText().toString(); 543 String[] emailParts = email.split("@"); 544 String user = emailParts[0].trim(); 545 String domain = emailParts[1].trim(); 546 547 // Alternate entry to the debug options screen (for devices without a physical keyboard: 548 // Username: d@d.d 549 // Password: debug 550 if (ENTER_DEBUG_SCREEN && "d@d.d".equals(email) && "debug".equals(password)) { 551 mEmailView.setText(""); 552 mPasswordView.setText(""); 553 AccountSettingsXL.actionSettingsWithDebug(this); 554 return; 555 } 556 557 Account account = SetupData.getAccount(); 558 HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); 559 recvAuth.setLogin(user, password); 560 recvAuth.setConnection("placeholder", domain, HostAuth.PORT_UNKNOWN, HostAuth.FLAG_NONE); 561 562 HostAuth sendAuth = account.getOrCreateHostAuthSend(this); 563 sendAuth.setLogin(user, password); 564 sendAuth.setConnection("placeholder", domain, HostAuth.PORT_UNKNOWN, HostAuth.FLAG_NONE); 565 566 populateSetupData(getOwnerName(), email, mDefaultView.isChecked()); 567 568 SetupData.setAllowAutodiscover(allowAutoDiscover); 569 AccountSetupAccountType.actionSelectAccountType(this); 570 } 571 572 /** 573 * To support continuous testing, we allow the forced creation of accounts. 574 * This works in a manner fairly similar to automatic setup, in which the complete server 575 * Uri's are available, except that we will also skip checking (as if both checks were true) 576 * and all other UI. 577 * 578 * @param email The email address for the new account 579 * @param user The user name for the new account 580 * @param incoming The URI-style string defining the incoming account 581 * @param outgoing The URI-style string defining the outgoing account 582 */ 583 private void forceCreateAccount(String email, String user, String incoming, String outgoing) { 584 Account account = SetupData.getAccount(); 585 try { 586 HostAuth recvAuth = account.getOrCreateHostAuthRecv(this); 587 Utility.setHostAuthFromString(recvAuth, incoming); 588 589 HostAuth sendAuth = account.getOrCreateHostAuthSend(this); 590 Utility.setHostAuthFromString(sendAuth, outgoing); 591 592 populateSetupData(user, email, false); 593 } catch (URISyntaxException e) { 594 // If we can't set up the URL, don't continue - account setup pages will fail too 595 Toast.makeText( 596 this, R.string.account_setup_username_password_toast, Toast.LENGTH_LONG).show(); 597 } 598 } 599 600 /** 601 * Populate SetupData's account with complete setup info. 602 */ 603 private void populateSetupData(String senderName, String senderEmail, boolean isDefault) { 604 Account account = SetupData.getAccount(); 605 account.setSenderName(senderName); 606 account.setEmailAddress(senderEmail); 607 account.setDisplayName(senderEmail); 608 account.setDefaultAccount(isDefault); 609 SetupData.setDefault(isDefault); // TODO - why duplicated, if already set in account 610 611 String protocol = account.mHostAuthRecv.mProtocol; 612 // Set sync and delete policies for specific inbound account types 613 if (Store.STORE_SCHEME_IMAP.equals(protocol)) { 614 // Delete policy must be set explicitly, because IMAP does not provide a UI selection 615 // for it. This logic needs to be followed in the auto setup flow as well. 616 account.setDeletePolicy(EmailContent.Account.DELETE_POLICY_ON_DELETE); 617 } 618 619 if (Store.STORE_SCHEME_EAS.equals(protocol)) { 620 account.setSyncInterval(Account.CHECK_INTERVAL_PUSH); 621 } else { 622 account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL); 623 } 624 } 625 626 /** 627 * Implements AccountCheckSettingsFragment.Callbacks 628 * 629 * This is used in automatic setup mode to jump directly down to the options screen. 630 * 631 * This is the only case where we finish() this activity but account setup is continuing, 632 * so we inhibit reporting any error back to the Account manager. 633 */ 634 @Override 635 public void onCheckSettingsComplete(int result) { 636 if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) { 637 AccountSetupOptions.actionOptions(this); 638 mReportAccountAuthenticatorError = false; 639 finish(); 640 } 641 } 642 643 /** 644 * Implements AccountCheckSettingsFragment.Callbacks 645 * This is overridden only by AccountSetupExchange 646 */ 647 @Override 648 public void onAutoDiscoverComplete(int result, HostAuth hostAuth) { 649 throw new IllegalStateException(); 650 } 651 652 /** 653 * AsyncTask checks count of accounts and displays "use this account as default" checkbox 654 * if there are more than one. 655 */ 656 private class DisplayCheckboxTask extends AsyncTask<Void, Void, Integer> { 657 658 @Override 659 protected Integer doInBackground(Void... params) { 660 return EmailContent.count(AccountSetupBasics.this, EmailContent.Account.CONTENT_URI); 661 } 662 663 @Override 664 protected void onPostExecute(Integer numAccounts) { 665 if (numAccounts > 0) { 666 Activity activity = AccountSetupBasics.this; 667 activity.findViewById(R.id.account_default_divider_1).setVisibility(View.VISIBLE); 668 mDefaultView.setVisibility(View.VISIBLE); 669 activity.findViewById(R.id.account_default_divider_2).setVisibility(View.VISIBLE); 670 } 671 } 672 } 673 674 private void onEnableProceedButtons(boolean enabled) { 675 mManualButton.setEnabled(enabled); 676 mNextButton.setEnabled(enabled); 677 } 678 679 /** 680 * Dialog fragment to show "setup note" dialog 681 */ 682 public static class NoteDialogFragment extends DialogFragment { 683 private final static String TAG = "NoteDialogFragment"; 684 685 // Argument bundle keys 686 private final static String BUNDLE_KEY_NOTE = "NoteDialogFragment.Note"; 687 688 /** 689 * Create the dialog with parameters 690 */ 691 public static NoteDialogFragment newInstance(String note) { 692 NoteDialogFragment f = new NoteDialogFragment(); 693 Bundle b = new Bundle(); 694 b.putString(BUNDLE_KEY_NOTE, note); 695 f.setArguments(b); 696 return f; 697 } 698 699 @Override 700 public Dialog onCreateDialog(Bundle savedInstanceState) { 701 Context context = getActivity(); 702 final String note = getArguments().getString(BUNDLE_KEY_NOTE); 703 704 return new AlertDialog.Builder(context) 705 .setIconAttribute(android.R.attr.alertDialogIcon) 706 .setTitle(android.R.string.dialog_alert_title) 707 .setMessage(note) 708 .setPositiveButton( 709 R.string.okay_action, 710 new DialogInterface.OnClickListener() { 711 public void onClick(DialogInterface dialog, int which) { 712 Activity a = getActivity(); 713 if (a instanceof AccountSetupBasics) { 714 ((AccountSetupBasics)a).finishAutoSetup(); 715 } 716 dismiss(); 717 } 718 }) 719 .setNegativeButton( 720 context.getString(R.string.cancel_action), 721 null) 722 .create(); 723 } 724 } 725} 726