Add magic intent to force account creation

* Add entry point via com.android.email.CREATE_ACCOUNT
* Enable when in monkey mode only
* Walks through setup screens as if auto-populated and as if
  connection checking always succeeds.
* Refactored some common code in AccountSetupBasicsFragment
* Removed obsolete commentary about auto-population of EAS accts
* Also fix minor typo in FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP

Bug: 2735784
Change-Id: Ie7363836cd267673e963e60ae8bc32cab422576e
This commit is contained in:
Andy Stadler 2010-12-04 22:53:59 -08:00
parent a097596f8b
commit d685b469c7
6 changed files with 137 additions and 43 deletions

View File

@ -107,11 +107,18 @@
>
</activity>
<!-- Must be exported in order for the AccountManager to launch it -->
<!-- Also available for continuous test systems to force account creation -->
<activity
android:name=".activity.setup.AccountSetupBasics"
android:label="@string/account_setup_basics_title"
android:exported="true"
>
<intent-filter>
<action
android:name="com.android.email.CREATE_ACCOUNT" />
<category
android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".activity.setup.AccountSetupAccountType"

View File

@ -16,6 +16,7 @@
package com.android.email.activity.setup;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.VendorPolicyLoader;
@ -27,10 +28,13 @@ import com.android.email.provider.EmailContent.HostAuth;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@ -44,11 +48,39 @@ import android.widget.Button;
*
* If the domain is not known, or the user selects Manual setup, we invoke the
* AccountSetupAccountType activity where the user can begin to manually configure the account.
*
* === Support for automated testing ==
* This activity can also be launched directly via ACTION_CREATE_ACCOUNT. This is intended
* only for use by continuous test systems, and is currently only available when "ro.monkey"
* is set. To use this mode, you must construct an intent which contains all necessary information
* to create the account. No connection checking is done, so the account may or may not actually
* work. Here is a sample command, for a gmail account "test_account" with a password of
* "test_password".
*
* $ adb shell am start -a com.android.email.CREATE_ACCOUNT \
* -e EMAIL test_account@gmail.com \
* -e USER "Test Account Name" \
* -e INCOMING imap+ssl+://test_account:test_password@imap.gmail.com \
* -e OUTGOING smtp+ssl+://test_account:test_password@smtp.gmail.com
*
* Note: For accounts that require the full email address in the login, encode the @ as %40.
* Note: Exchange accounts that require device security policies cannot be created automatically.
*/
public class AccountSetupBasics extends AccountSetupActivity
implements AccountSetupBasicsFragment.Callback, AccountCheckSettingsFragment.Callbacks,
OnClickListener {
/**
* Direct access for forcing account creation
* For use by continuous automated test system (e.g. in conjunction with monkey tests)
*/
private final String ACTION_CREATE_ACCOUNT = "com.android.email.CREATE_ACCOUNT";
private final String EXTRA_CREATE_ACCOUNT_EMAIL = "EMAIL";
private final String EXTRA_CREATE_ACCOUNT_USER = "USER";
private final String EXTRA_CREATE_ACCOUNT_INCOMING = "INCOMING";
private final String EXTRA_CREATE_ACCOUNT_OUTGOING = "OUTGOING";
private final Boolean DEBUG_ALLOW_NON_MONKEY_CREATION = false; // DO NOT CHECK IN "TRUE"
private AccountSetupBasicsFragment mFragment;
private boolean mManualButtonDisplayed;
private boolean mNextButtonEnabled;
@ -80,7 +112,7 @@ public class AccountSetupBasics extends AccountSetupActivity
* for pop/imap accounts.
*/
public static Intent actionSetupPopImapIntent(Context context) {
SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MAANGER_POP_IMAP);
SetupData.init(SetupData.FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP);
return new Intent(context, AccountSetupBasics.class);
}
@ -112,6 +144,13 @@ public class AccountSetupBasics extends AccountSetupActivity
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
// Check for forced account creation first, as it comes from an externally-generated
// intent and won't have any SetupData prepared.
String action = getIntent().getAction();
if (ACTION_CREATE_ACCOUNT.equals(action)) {
SetupData.init(SetupData.FLOW_MODE_FORCE_CREATE);
}
int flowMode = SetupData.getFlowMode();
if (flowMode == SetupData.FLOW_MODE_RETURN_TO_CALLER) {
// Return to the caller who initiated account creation
@ -162,6 +201,31 @@ public class AccountSetupBasics extends AccountSetupActivity
if (mAccountAuthenticatorResponse != null) {
mAccountAuthenticatorResponse.onRequestContinued();
}
// Handle force account creation immediately (now that fragment is set up)
// This is never allowed in a normal user build and will exit immediately.
if (SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) {
if (!DEBUG_ALLOW_NON_MONKEY_CREATION && !ActivityManager.isUserAMonkey()) {
Log.e(Email.LOG_TAG, "ERROR: Force account create only allowed for monkeys");
finish();
return;
}
Intent intent = getIntent();
String email = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_EMAIL);
String user = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_USER);
String incoming = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_INCOMING);
String outgoing = intent.getStringExtra(EXTRA_CREATE_ACCOUNT_OUTGOING);
if (TextUtils.isEmpty(email) || TextUtils.isEmpty(user) ||
TextUtils.isEmpty(incoming) || TextUtils.isEmpty(outgoing)) {
Log.e(Email.LOG_TAG, "ERROR: Force account create requires extras EMAIL, USER, " +
"INCOMING, OUTGOING");
finish();
return;
}
mFragment.forceCreateAccount(email, user, incoming, outgoing);
onCheckSettingsComplete(AccountCheckSettingsFragment.CHECK_SETTINGS_OK); // calls finish
return;
}
}
@Override
@ -182,11 +246,7 @@ public class AccountSetupBasics extends AccountSetupActivity
/**
* Implements AccountCheckSettingsFragment.Callbacks
*
* This is used in automatic setup mode to jump directly down to the names screen.
*
* NOTE: With this organization, it is *not* possible to auto-create an exchange account,
* because certain necessary actions happen during AccountSetupOptions (which we are
* skipping here).
* This is used in automatic setup mode to jump directly down to the options screen.
*/
@Override
public void onCheckSettingsComplete(int result) {

View File

@ -374,26 +374,9 @@ public class AccountSetupBasicsFragment extends Fragment implements TextWatcher
return;
}
Account account = SetupData.getAccount();
account.setSenderName(getOwnerName());
account.setEmailAddress(email);
account.setDisplayName(email);
boolean isDefault = mDefaultView.isChecked();
account.setDefaultAccount(isDefault);
SetupData.setDefault(isDefault); // TODO - why duplicated, if already set in account
account.setStoreUri(mContext, incomingUri.toString());
account.setSenderUri(mContext, outgoingUri.toString());
String incomingUriString = incomingUri.toString();
if (incomingUriString.startsWith("imap")) {
// Delete policy must be set explicitly, because IMAP does not provide a UI selection
// for it. This logic needs to be followed in the auto setup flow as well.
account.setDeletePolicy(EmailContent.Account.DELETE_POLICY_ON_DELETE);
}
if (incomingUriString.startsWith("eas")) {
account.setSyncInterval(Account.CHECK_INTERVAL_PUSH);
} else {
account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL);
}
populateSetupData(getOwnerName(), email, mDefaultView.isChecked(),
incomingUri.toString(), outgoingUri.toString());
mCallback.onProceedAutomatic();
}
@ -446,29 +429,65 @@ public class AccountSetupBasicsFragment extends Fragment implements TextWatcher
return;
}
Account account = SetupData.getAccount();
account.setSenderName(getOwnerName());
account.setEmailAddress(email);
account.setDisplayName(email);
boolean isDefault = mDefaultView.isChecked();
account.setDefaultAccount(isDefault);
SetupData.setDefault(isDefault); // TODO - why duplicated, if already set in account
String uriString = null;
try {
URI uri = new URI("placeholder", user + ":" + password, domain, -1, null, null, null);
account.setStoreUri(mContext, uri.toString());
account.setSenderUri(mContext, uri.toString());
uriString = uri.toString();
} catch (URISyntaxException use) {
// If we can't set up the URL, don't continue - account setup pages will fail too
Toast.makeText(mContext, R.string.account_setup_username_password_toast,
Toast.LENGTH_LONG).show();
account = null;
return;
}
account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL);
populateSetupData(getOwnerName(), email, mDefaultView.isChecked(), uriString, uriString);
mCallback.onProceedManual(allowAutoDiscover);
}
/**
* To support continuous testing, we allow the forced creation of accounts.
* This works in a manner fairly similar to automatic setup, in which the complete server
* Uri's are available, except that we will also skip checking (as if both checks were true)
* and all other UI.
*
* @param email The email address for the new account
* @param user The user name for the new account
* @param incoming The URI-style string defining the incoming account
* @param outgoing The URI-style string defining the outgoing account
*/
public void forceCreateAccount(String email, String user, String incoming, String outgoing) {
populateSetupData(user, email, false, incoming, outgoing);
}
/**
* Populate SetupData's account with complete setup info.
*/
private void populateSetupData(String senderName, String senderEmail, boolean isDefault,
String incoming, String outgoing) {
Account account = SetupData.getAccount();
account.setSenderName(senderName);
account.setEmailAddress(senderEmail);
account.setDisplayName(senderEmail);
account.setDefaultAccount(isDefault);
SetupData.setDefault(isDefault); // TODO - why duplicated, if already set in account
account.setStoreUri(mContext, incoming);
account.setSenderUri(mContext, outgoing);
// Set sync and delete policies for specific account types
if (incoming.startsWith("imap")) {
// Delete policy must be set explicitly, because IMAP does not provide a UI selection
// for it. This logic needs to be followed in the auto setup flow as well.
account.setDeletePolicy(EmailContent.Account.DELETE_POLICY_ON_DELETE);
}
if (incoming.startsWith("eas")) {
account.setSyncInterval(Account.CHECK_INTERVAL_PUSH);
} else {
account.setSyncInterval(DEFAULT_ACCOUNT_CHECK_INTERVAL);
}
}
/**
* Dialog fragment to show "setup note" dialog
*/
@ -516,5 +535,4 @@ public class AccountSetupBasicsFragment extends Fragment implements TextWatcher
.create();
}
}
}

View File

@ -108,6 +108,11 @@ public class AccountSetupNames extends AccountSetupActivity implements OnClickLi
// Make sure the "done" button is in the proper state
validateFields();
// Proceed immediately if in account creation mode
if (SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) {
onNext();
}
}
@Override

View File

@ -136,7 +136,9 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
findViewById(R.id.account_sync_calendar_divider).setVisibility(View.VISIBLE);
}
if (SetupData.isAutoSetup()) {
// If we are just visiting here to fill in details, exit immediately
if (SetupData.isAutoSetup() ||
SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) {
onDone();
}
}

View File

@ -31,15 +31,17 @@ public class SetupData implements Parcelable {
// Settings -> Accounts
public static final int FLOW_MODE_NORMAL = 0;
public static final int FLOW_MODE_ACCOUNT_MANAGER_EAS = 1;
public static final int FLOW_MODE_ACCOUNT_MAANGER_POP_IMAP = 2;
public static final int FLOW_MODE_ACCOUNT_MANAGER_POP_IMAP = 2;
public static final int FLOW_MODE_EDIT = 3;
public static final int FLOW_MODE_FORCE_CREATE = 4;
// The following two modes are used to "pop the stack" and return from the setup flow. We
// either return to the caller (if we're in an account type flow) or go to the message list
public static final int FLOW_MODE_RETURN_TO_CALLER = 4;
public static final int FLOW_MODE_RETURN_TO_MESSAGE_LIST = 5;
public static final int FLOW_MODE_RETURN_TO_CALLER = 5;
public static final int FLOW_MODE_RETURN_TO_MESSAGE_LIST = 6;
// For debug logging
private static final String[] FLOW_MODES = {"normal", "eas", "pop/imap", "edit", "rtc", "rtl"};
private static final String[] FLOW_MODES = {"normal", "eas", "pop/imap", "edit", "force",
"rtc", "rtl"};
// Mode bits for AccountSetupCheckSettings, indicating the type of check requested
public static final int CHECK_INCOMING = 1;