Merge "Direct access to edit specific account settings"

This commit is contained in:
Andrew Stadler 2010-09-01 21:20:41 -07:00 committed by Android (Google) Code Review
commit bf2a53ef5e
5 changed files with 103 additions and 221 deletions

View File

@ -135,22 +135,14 @@
>
</activity>
<activity
android:name=".activity.setup.AccountSettings"
android:name=".activity.setup.AccountSettingsXL"
android:label="@string/account_settings_action"
android:theme="@android:style/Theme"
>
<intent-filter>
<action android:name="com.android.email.activity.setup.ACCOUNT_MANAGER_ENTRY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- STOPSHIP - AccountSettingsXL is a parallel implementation and eventually
it simply replaces activity.setup.AccountSettings -->
<activity
android:name=".activity.setup.AccountSettingsXL"
android:label="@string/account_settings_action"
>
</activity>
<activity
android:name=".activity.setup.AccountSecurity"
android.label="@string/account_security_title"

View File

@ -119,7 +119,6 @@
android:summary="@string/account_settings_sync_calendar_summary" />
</PreferenceCategory>
<!-- TODO This is a temporary home for delete account -->
<PreferenceCategory
android:title="@string/account_settings_category_delete_account">

View File

@ -1,184 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity.setup;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.activity.Welcome;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
/**
* TODO: At this point this is used only to support the Account Manager, and needs to be removed.
*/
public class AccountSettings extends Activity
implements AccountSettingsFragment.Callback, AccountSettingsFragment.OnAttachListener {
// NOTE: This string must match the one in res/xml/account_preferences.xml
private static final String ACTION_ACCOUNT_MANAGER_ENTRY =
"com.android.email.activity.setup.ACCOUNT_MANAGER_ENTRY";
// NOTE: This constant should eventually be defined in android.accounts.Constants, but for
// now we define it here
private static final String ACCOUNT_MANAGER_EXTRA_ACCOUNT = "account";
private static final String EXTRA_ACCOUNT_ID = "account_id";
// UI values
/* package */ AccountSettingsFragment mFragment;
// Account data values
private long mAccountId = -1;
/**
* Display (and edit) settings for a specific account
*/
public static void actionSettings(Activity fromActivity, long accountId) {
Intent i = new Intent(fromActivity, AccountSettings.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
fromActivity.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
if (ACTION_ACCOUNT_MANAGER_ENTRY.equals(i.getAction())) {
// This case occurs if we're changing account settings from Settings -> Accounts
setAccountIdFromAccountManagerIntent();
} else {
// Otherwise, we're called from within the Email app and look for our extra
mAccountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
}
// If there's no accountId, we're done
if (mAccountId == -1) {
finish();
return;
}
// Now set up the UI and the fragment
setContentView(R.layout.account_settings);
mFragment = (AccountSettingsFragment)
getFragmentManager().findFragmentById(R.id.settings_fragment);
mFragment.setCallback(this);
mFragment.startLoadingAccount(mAccountId);
}
private void setAccountIdFromAccountManagerIntent() {
// First, get the AccountManager account that we've been ask to handle
android.accounts.Account acct =
(android.accounts.Account)getIntent()
.getParcelableExtra(ACCOUNT_MANAGER_EXTRA_ACCOUNT);
// Find a HostAuth using eas and whose login is the name of the AccountManager account
Cursor c = getContentResolver().query(Account.CONTENT_URI,
new String[] {AccountColumns.ID}, AccountColumns.EMAIL_ADDRESS + "=?",
new String[] {acct.name}, null);
try {
if (c.moveToFirst()) {
mAccountId = c.getLong(0);
}
} finally {
c.close();
}
}
@Override
public void onResume() {
super.onResume();
// Exit immediately if the accounts list has changed (e.g. externally deleted)
if (Email.getNotifyUiAccountsChanged()) {
Welcome.actionStart(this);
finish();
return;
}
}
/**
* Implements AccountSettingsFragment.Callback
*/
@Override
public void onIncomingSettings(Account account) {
try {
Store store = Store.getInstance(account.getStoreUri(this), getApplication(), null);
if (store != null) {
Class<? extends android.app.Activity> setting = store.getSettingActivityClass();
if (setting != null) {
java.lang.reflect.Method m = setting.getMethod("actionEditIncomingSettings",
Activity.class, int.class, Account.class);
m.invoke(null, this, SetupData.FLOW_MODE_EDIT, account);
}
}
} catch (Exception e) {
Log.d(Email.LOG_TAG, "Error while trying to invoke store settings.", e);
}
}
/**
* Implements AccountSettingsFragment.Callback
*/
@Override
public void onOutgoingSettings(Account account) {
try {
Sender sender = Sender.getInstance(getApplication(), account.getSenderUri(this));
if (sender != null) {
Class<? extends android.app.Activity> setting = sender.getSettingActivityClass();
if (setting != null) {
java.lang.reflect.Method m = setting.getMethod("actionEditOutgoingSettings",
Activity.class, int.class, Account.class);
m.invoke(null, this, SetupData.FLOW_MODE_EDIT, account);
}
}
} catch (Exception e) {
Log.d(Email.LOG_TAG, "Error while trying to invoke sender settings.", e);
}
}
/**
* Implements AccountSettingsFragment.Callback
*/
@Override
public void abandonEdit() {
finish();
}
/**
* Implements AccountSettingsFragment.Callback
*/
@Override
public void deleteAccount(Account account) {
// STOPSHIP - this is not implemented because this entire activity is deprecated
// If you need to delete an account, use the AccountSettingsXL, which will eventually
// become the only settings activity.
}
/**
* Implements AccountSettingsFragment.OnAttachListener
* Does nothing (this activity sets up the fragment in onCreate via its layout)
*/
@Override
public void onAttach(Fragment f) {
}
}

View File

@ -24,6 +24,7 @@ import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.service.MailService;
import android.app.Activity;
@ -46,8 +47,6 @@ import java.util.List;
/**
* Handles account preferences using multi-pane arrangement when possible.
*
* TODO: Go directly to specific account when requested - post runnable after onBuildHeaders
* TODO: Incorporate entry point & other stuff to support launch from AccountManager
* TODO: In Account settings in Phone UI, change title
* TODO: Rework all remaining calls to DB from UI thread
* TODO: Delete account - on single-pane view (phone UX) the account list doesn't update properly
@ -58,9 +57,17 @@ import java.util.List;
public class AccountSettingsXL extends PreferenceActivity
implements AccountSettingsFragment.OnAttachListener, OnClickListener {
private static final String EXTRA_ACCOUNT_ID = "AccountSettingsXL.account_id";
// Intent extras for our internal activity launch
/* package */ static final String EXTRA_ACCOUNT_ID = "AccountSettingsXL.account_id";
private static final String EXTRA_ENABLE_DEBUG = "AccountSettingsXL.enable_debug";
// Intent extras for launch directly from system account manager
// NOTE: This string must match the one in res/xml/account_preferences.xml
private static final String ACTION_ACCOUNT_MANAGER_ENTRY =
"com.android.email.activity.setup.ACCOUNT_MANAGER_ENTRY";
// NOTE: This constant should eventually be defined in android.accounts.Constants
private static final String EXTRA_ACCOUNT_MANAGER_ACCOUNT = "account";
// Key codes used to open a debug settings fragment.
private static final int[] SECRET_KEY_CODES = {
KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_U,
@ -68,22 +75,26 @@ public class AccountSettingsXL extends PreferenceActivity
};
private int mSecretKeyCodeIndex = 0;
/**
* When the user taps "Email Preferences" 10 times in a row, we'll enable the debug settings.
*/
// Support for account-by-name lookup
private static final String SELECTION_ACCOUNT_EMAIL_ADDRESS =
AccountColumns.EMAIL_ADDRESS + "=?";
// When the user taps "Email Preferences" 10 times in a row, we'll enable the debug settings.
private int mNumGeneralHeaderClicked = 0;
private long mRequestedAccountId;
private Header mRequestedAccountHeader;
private ExtendedHeader[] mAccountListHeaders;
private Header mAppPreferencesHeader;
private int mCurrentHeaderPosition;
private Fragment mCurrentFragment;
/* package */ Fragment mCurrentFragment;
private long mDeletingAccountId = -1;
private boolean mShowDebugMenu;
private Button mAddAccountButton;
// Async Tasks
private LoadAccountListTask mLoadAccountListTask;
private GetAccountIdFromAccountTask mGetAccountIdFromAccountTask;
// Specific callbacks used by settings fragments
private AccountSettingsFragmentCallback mAccountSettingsFragmentCallback
@ -113,7 +124,14 @@ public class AccountSettingsXL extends PreferenceActivity
super.onCreate(savedInstanceState);
Intent i = getIntent();
mRequestedAccountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
if (ACTION_ACCOUNT_MANAGER_ENTRY.equals(i.getAction())) {
// This case occurs if we're changing account settings from Settings -> Accounts
mGetAccountIdFromAccountTask =
(GetAccountIdFromAccountTask) new GetAccountIdFromAccountTask().execute(i);
} else {
// Otherwise, we're called from within the Email app and look for our extra
mRequestedAccountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
}
mShowDebugMenu = i.getBooleanExtra(EXTRA_ENABLE_DEBUG, false);
// Add Account as header list footer
@ -139,6 +157,8 @@ public class AccountSettingsXL extends PreferenceActivity
super.onDestroy();
Utility.cancelTaskInterrupt(mLoadAccountListTask);
mLoadAccountListTask = null;
Utility.cancelTaskInterrupt(mGetAccountIdFromAccountTask);
mGetAccountIdFromAccountTask = null;
}
/**
@ -165,6 +185,17 @@ public class AccountSettingsXL extends PreferenceActivity
}
}
/**
* If the caller requested a specific account to be edited, switch to it. This is a one-shot,
* so the user is free to edit another account as well.
*/
@Override
public Header onGetNewHeader() {
Header result = mRequestedAccountHeader;
mRequestedAccountHeader = null;
return result;
}
private void enableDebugMenu() {
mShowDebugMenu = true;
invalidateHeaders();
@ -206,22 +237,32 @@ public class AccountSettingsXL extends PreferenceActivity
/**
* Write the current header (accounts) array into the one provided by the PreferenceActivity.
* Skip any headers that match mDeletingAccountId (this is a quick-hide algorithm while a
* background thread works on deleting the account).
* background thread works on deleting the account). Also sets mRequestedAccountHeader if
* we find the requested account (by id).
*/
@Override
public void onBuildHeaders(List<Header> target) {
// Assume the account is unspecified
mRequestedAccountHeader = null;
// Always add app preferences as first header
target.clear();
target.add(getAppPreferencesHeader());
// Then add zero or more account headers as necessary
if (mAccountListHeaders != null) {
int headerCount = mAccountListHeaders.length;
for (int index = 0; index < headerCount; index++) {
if (mAccountListHeaders[index].accountId != mDeletingAccountId) {
target.add(mAccountListHeaders[index]);
ExtendedHeader header = mAccountListHeaders[index];
if (header.accountId != mDeletingAccountId) {
target.add(header);
if (header.accountId == mRequestedAccountId) {
mRequestedAccountHeader = header;
}
}
}
}
// finally, if debug header is enabled, show it
if (mShowDebugMenu) {
// setup lightweight header for debugging
@ -259,7 +300,7 @@ public class AccountSettingsXL extends PreferenceActivity
* for quick scans, etc.
*/
private class ExtendedHeader extends Header {
public long accountId;
public final long accountId;
public ExtendedHeader(long _accountId, String _title, String _summary) {
title = _title;
@ -453,6 +494,32 @@ public class AccountSettingsXL extends PreferenceActivity
}
}
/**
* This AsyncTask looks up an account based on its email address (which is what we get from
* the Account Manager). When the account id is determined, we refresh the header list,
* which will select the preferences for that account.
*/
private class GetAccountIdFromAccountTask extends AsyncTask<Intent, Void, Long> {
@Override
protected Long doInBackground(Intent... params) {
Intent intent = params[0];
android.accounts.Account acct =
(android.accounts.Account) intent.getParcelableExtra(EXTRA_ACCOUNT_MANAGER_ACCOUNT);
return Utility.getFirstRowLong(AccountSettingsXL.this, Account.CONTENT_URI,
Account.ID_PROJECTION, SELECTION_ACCOUNT_EMAIL_ADDRESS, new String[] {acct.name},
null, Account.ID_PROJECTION_COLUMN, -1L);
}
@Override
protected void onPostExecute(Long accountId) {
if (accountId != -1 && !isCancelled()) {
mRequestedAccountId = accountId;
AccountSettingsXL.this.invalidateHeaders();
}
}
}
/**
* Placeholder for app-wide preferences
* STOPSHIP - make this real

View File

@ -24,29 +24,30 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
/**
* Tests of basic UI logic in the AccountSettings screen.
* Tests of basic UI logic in the Account Settings fragment.
*
* TODO: This should use a local provider for the test "accounts", and not touch user data
*
* To execute: runtest -c com.android.email.activity.setup.AccountSettingsXLTests email
*/
@MediumTest
public class AccountSettingsTests extends ActivityInstrumentationTestCase2<AccountSettings> {
// Borrowed from AccountSettings
private static final String EXTRA_ACCOUNT_ID = "account_id";
public class AccountSettingsXLTests extends ActivityInstrumentationTestCase2<AccountSettingsXL> {
private long mAccountId;
private Account mAccount;
private Context mContext;
private AccountSettings mActivity;
private ListPreference mCheckFrequency;
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
public AccountSettingsTests() {
super(AccountSettings.class);
public AccountSettingsXLTests() {
super(AccountSettingsXL.class);
}
/**
@ -76,7 +77,7 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
/**
* Test that POP accounts aren't displayed with a push option
*/
public void testPushOptionPOP() {
public void testPushOptionPOP() throws Throwable {
Intent i = getTestIntent("Name", "pop3://user:password@server.com",
"smtp://user:password@server.com");
this.setActivityIntent(i);
@ -90,7 +91,7 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
/**
* Test that IMAP accounts aren't displayed with a push option
*/
public void testPushOptionIMAP() {
public void testPushOptionIMAP() throws Throwable {
Intent i = getTestIntent("Name", "imap://user:password@server.com",
"smtp://user:password@server.com");
this.setActivityIntent(i);
@ -104,7 +105,7 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
/**
* Test that EAS accounts are displayed with a push option
*/
public void testPushOptionEAS() {
public void testPushOptionEAS() throws Throwable {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", this.getInstrumentation().getTargetContext())
== null) {
@ -124,9 +125,16 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
/**
* Get the activity (which causes it to be started, using our intent) and get the UI fields
*/
private void getActivityAndFields() {
mActivity = getActivity();
mCheckFrequency = (ListPreference) mActivity.mFragment.findPreference(PREFERENCE_FREQUENCY);
private void getActivityAndFields() throws Throwable {
final AccountSettingsXL theActivity = getActivity();
runTestOnUiThread(new Runnable() {
public void run() {
PreferenceFragment f = (PreferenceFragment) theActivity.mCurrentFragment;
AccountSettingsXLTests.this.mCheckFrequency =
(ListPreference) f.findPreference(PREFERENCE_FREQUENCY);
}
});
}
/**
@ -156,7 +164,7 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
mAccountId = mAccount.mId;
Intent i = new Intent(Intent.ACTION_MAIN);
i.putExtra(EXTRA_ACCOUNT_ID, mAccountId);
i.putExtra(AccountSettingsXL.EXTRA_ACCOUNT_ID, mAccountId);
return i;
}