AccountSetupBasics.java revision d685b469c73c3479c09301da2e65cd7c11fd4ace
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.R; 21import com.android.email.Utility; 22import com.android.email.VendorPolicyLoader; 23import com.android.email.activity.ActivityHelper; 24import com.android.email.activity.Welcome; 25import com.android.email.provider.EmailContent.Account; 26import com.android.email.provider.EmailContent.HostAuth; 27 28import android.accounts.AccountAuthenticatorResponse; 29import android.accounts.AccountManager; 30import android.app.Activity; 31import android.app.ActivityManager; 32import android.app.FragmentTransaction; 33import android.content.Context; 34import android.content.Intent; 35import android.os.Bundle; 36import android.text.TextUtils; 37import android.util.Log; 38import android.view.View; 39import android.view.View.OnClickListener; 40import android.widget.Button; 41 42/** 43 * Prompts the user for the email address and password. Also prompts for "Use this account as 44 * default" if this is the 2nd+ account being set up. 45 * 46 * If the domain is well-known, the account is configured fully and checked immediately 47 * using AccountCheckSettingsFragment. If this succeeds we proceed directly to AccountSetupOptions. 48 * 49 * If the domain is not known, or the user selects Manual setup, we invoke the 50 * AccountSetupAccountType activity where the user can begin to manually configure the account. 51 * 52 * === Support for automated testing == 53 * This activity can also be launched directly via ACTION_CREATE_ACCOUNT. This is intended 54 * only for use by continuous test systems, and is currently only available when "ro.monkey" 55 * is set. To use this mode, you must construct an intent which contains all necessary information 56 * to create the account. No connection checking is done, so the account may or may not actually 57 * work. Here is a sample command, for a gmail account "test_account" with a password of 58 * "test_password". 59 * 60 * $ adb shell am start -a com.android.email.CREATE_ACCOUNT \ 61 * -e EMAIL test_account@gmail.com \ 62 * -e USER "Test Account Name" \ 63 * -e INCOMING imap+ssl+://test_account:test_password@imap.gmail.com \ 64 * -e OUTGOING smtp+ssl+://test_account:test_password@smtp.gmail.com 65 * 66 * Note: For accounts that require the full email address in the login, encode the @ as %40. 67 * Note: Exchange accounts that require device security policies cannot be created automatically. 68 */ 69public class AccountSetupBasics extends AccountSetupActivity 70 implements AccountSetupBasicsFragment.Callback, AccountCheckSettingsFragment.Callbacks, 71 OnClickListener { 72 73 /** 74 * Direct access for forcing account creation 75 * For use by continuous automated test system (e.g. in conjunction with monkey tests) 76 */ 77 private final String ACTION_CREATE_ACCOUNT = "com.android.email.CREATE_ACCOUNT"; 78 private final String EXTRA_CREATE_ACCOUNT_EMAIL = "EMAIL"; 79 private final String EXTRA_CREATE_ACCOUNT_USER = "USER"; 80 private final String EXTRA_CREATE_ACCOUNT_INCOMING = "INCOMING"; 81 private final String EXTRA_CREATE_ACCOUNT_OUTGOING = "OUTGOING"; 82 private final Boolean DEBUG_ALLOW_NON_MONKEY_CREATION = false; // DO NOT CHECK IN "TRUE" 83 84 private AccountSetupBasicsFragment mFragment; 85 private boolean mManualButtonDisplayed; 86 private boolean mNextButtonEnabled; 87 private Button mManualButton; 88 private Button mNextButton; 89 90 // Used when this Activity is called as part of account authentification flow, 91 // which requires to do extra work before and after the account creation. 92 // See also AccountAuthenticatorActivity. 93 private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null; 94 private Bundle mResultBundle = null; 95 96 public static void actionNewAccount(Activity fromActivity) { 97 SetupData.init(SetupData.FLOW_MODE_NORMAL); 98 fromActivity.startActivity(new Intent(fromActivity, AccountSetupBasics.class)); 99 } 100 101 /** 102 * This generates setup data that can be used to start a self-contained account creation flow 103 * for exchange accounts. 104 */ 105 public static Intent actionSetupExchangeIntent(Context context) { 106 SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS); 107 return new Intent(context, AccountSetupBasics.class); 108 } 109 110 /** 111 * This generates setup data that can be used to start a self-contained account creation flow 112 * for pop/imap accounts. 113 */ 114 public static Intent actionSetupPopImapIntent(Context context) { 115 SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP); 116 return new Intent(context, AccountSetupBasics.class); 117 } 118 119 public static void actionAccountCreateFinishedAccountFlow(Activity fromActivity) { 120 Intent i= new Intent(fromActivity, AccountSetupBasics.class); 121 // If we're in the "account flow" (from AccountManager), we want to return to the caller 122 // (in the settings app) 123 SetupData.init(SetupData.FLOW_MODE_RETURN_TO_CALLER); 124 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 125 fromActivity.startActivity(i); 126 } 127 128 public static void actionAccountCreateFinished(final Activity fromActivity, 129 final long accountId) { 130 Utility.runAsync(new Runnable() { 131 public void run() { 132 Intent i = new Intent(fromActivity, AccountSetupBasics.class); 133 // If we're not in the "account flow" (from AccountManager), we want to show the 134 // message list for the new inbox 135 Account account = Account.restoreAccountWithId(fromActivity, accountId); 136 SetupData.init(SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST, account); 137 i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 138 fromActivity.startActivity(i); 139 }}); 140 } 141 142 @Override 143 public void onCreate(Bundle savedInstanceState) { 144 super.onCreate(savedInstanceState); 145 ActivityHelper.debugSetWindowFlags(this); 146 147 // Check for forced account creation first, as it comes from an externally-generated 148 // intent and won't have any SetupData prepared. 149 String action = getIntent().getAction(); 150 if (ACTION_CREATE_ACCOUNT.equals(action)) { 151 SetupData.init(SetupData.FLOW_MODE_FORCE_CREATE); 152 } 153 154 int flowMode = SetupData.getFlowMode(); 155 if (flowMode == SetupData.FLOW_MODE_RETURN_TO_CALLER) { 156 // Return to the caller who initiated account creation 157 finish(); 158 return; 159 } else if (flowMode == SetupData.FLOW_MODE_RETURN_TO_MESSAGE_LIST) { 160 Account account = SetupData.getAccount(); 161 if (account != null && account.mId >= 0) { 162 // Show the message list for the new account 163 Welcome.actionOpenAccountInbox(this, account.mId); 164 finish(); 165 return; 166 } 167 } 168 169 setContentView(R.layout.account_setup_basics); 170 171 mFragment = (AccountSetupBasicsFragment) 172 getFragmentManager().findFragmentById(R.id.setup_basics_fragment); 173 mManualButtonDisplayed = true; 174 boolean alternateStrings = false; 175 if (flowMode == SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) { 176 // No need for manual button -> next is appropriate 177 mManualButtonDisplayed = false; 178 // Swap welcome text for EAS-specific text 179 alternateStrings = VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings(); 180 setTitle(alternateStrings 181 ? R.string.account_setup_basics_exchange_title_alternate 182 : R.string.account_setup_basics_exchange_title); 183 } 184 185 // Configure fragment 186 mFragment.setCallback(this, alternateStrings); 187 188 // Configure buttons 189 mManualButton = (Button) findViewById(R.id.manual_setup); 190 mNextButton = (Button) findViewById(R.id.next); 191 mManualButton.setVisibility(mManualButtonDisplayed ? View.VISIBLE : View.INVISIBLE); 192 mManualButton.setOnClickListener(this); 193 mNextButton.setOnClickListener(this); 194 // Force disabled until fragment notifies otherwise 195 mNextButtonEnabled = true; 196 this.onEnableProceedButtons(false); 197 198 mAccountAuthenticatorResponse = 199 getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE); 200 201 if (mAccountAuthenticatorResponse != null) { 202 mAccountAuthenticatorResponse.onRequestContinued(); 203 } 204 205 // Handle force account creation immediately (now that fragment is set up) 206 // This is never allowed in a normal user build and will exit immediately. 207 if (SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) { 208 if (!DEBUG_ALLOW_NON_MONKEY_CREATION && !ActivityManager.isUserAMonkey()) { 209 Log.e(Email.LOG_TAG, "ERROR: Force account create only allowed for monkeys"); 210 finish(); 211 return; 212 } 213 Intent intent = getIntent(); 214 String email = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_EMAIL); 215 String user = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_USER); 216 String incoming = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_INCOMING); 217 String outgoing = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_OUTGOING); 218 if (TextUtils.isEmpty(email) || TextUtils.isEmpty(user) || 219 TextUtils.isEmpty(incoming) || TextUtils.isEmpty(outgoing)) { 220 Log.e(Email.LOG_TAG, "ERROR: Force account create requires extras EMAIL, USER, " + 221 "INCOMING, OUTGOING"); 222 finish(); 223 return; 224 } 225 mFragment.forceCreateAccount(email, user, incoming, outgoing); 226 onCheckSettingsComplete(AccountCheckSettingsFragment.CHECK_SETTINGS_OK); // calls finish 227 return; 228 } 229 } 230 231 @Override 232 public void finish() { 233 if (mAccountAuthenticatorResponse != null) { 234 // send the result bundle back if set, otherwise send an error. 235 if (mResultBundle != null) { 236 mAccountAuthenticatorResponse.onResult(mResultBundle); 237 } else { 238 mAccountAuthenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED, 239 "canceled"); 240 } 241 mAccountAuthenticatorResponse = null; 242 } 243 super.finish(); 244 } 245 246 /** 247 * Implements AccountCheckSettingsFragment.Callbacks 248 * 249 * This is used in automatic setup mode to jump directly down to the options screen. 250 */ 251 @Override 252 public void onCheckSettingsComplete(int result) { 253 if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) { 254 AccountSetupOptions.actionOptions(this); 255 finish(); 256 } 257 } 258 259 /** 260 * Implements AccountCheckSettingsFragment.Callbacks 261 * This is overridden only by AccountSetupExchange 262 */ 263 @Override 264 public void onAutoDiscoverComplete(int result, HostAuth hostAuth) { 265 throw new IllegalStateException(); 266 } 267 268 /** 269 * Implements OnClickListener 270 */ 271 @Override 272 public void onClick(View v) { 273 switch (v.getId()) { 274 case R.id.next: 275 mFragment.onNext(); 276 break; 277 case R.id.manual_setup: 278 // no AutoDiscover - user clicked "manual" 279 mFragment.onManualSetup(false); 280 break; 281 } 282 } 283 284 /** 285 * Implements AccountSetupBasicsFragment.Callback 286 */ 287 @Override 288 public void onEnableProceedButtons(boolean enabled) { 289 boolean wasEnabled = mNextButtonEnabled; 290 mNextButtonEnabled = enabled; 291 292 if (enabled != wasEnabled) { 293 mManualButton.setEnabled(enabled); 294 mNextButton.setEnabled(enabled); 295 } 296 } 297 298 /** 299 * Implements AccountSetupBasicsFragment.Callback 300 * 301 * This is called when auto-setup (from hardcoded server info) is attempted. 302 * Replace the name/password fragment with the account checker, which will begin to 303 * check incoming/outgoing. 304 */ 305 @Override 306 public void onProceedAutomatic() { 307 AccountCheckSettingsFragment checkerFragment = 308 AccountCheckSettingsFragment.newInstance( 309 SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING, null); 310 FragmentTransaction transaction = getFragmentManager().openTransaction(); 311 transaction.replace(R.id.setup_basics_fragment, checkerFragment); 312 transaction.addToBackStack("back"); 313 transaction.commit(); 314 } 315 316 /** 317 * Implements AccountSetupBasicsFragment.Callback 318 */ 319 @Override 320 public void onProceedDebugSettings() { 321 AccountSettingsXL.actionSettingsWithDebug(this); 322 } 323 324 /** 325 * Implements AccountSetupBasicsFragment.Callback 326 */ 327 @Override 328 public void onProceedManual(boolean allowAutoDiscover) { 329 SetupData.setAllowAutodiscover(allowAutoDiscover); 330 AccountSetupAccountType.actionSelectAccountType(this); 331 } 332} 333