Add Add & Remove Account options to AccountSettingsXL

* Add account is a large (+) in the action bar
* Remove account is a new item at the bottom of the settings fragment
Note: Add account works, remove account just toasts for now.

Change-Id: I5b3b8ab8c7d328cb78d103c47b9eca866466f9df
This commit is contained in:
Andrew Stadler 2010-08-19 16:28:52 -07:00
parent 7894ee82b3
commit a14a24a5bc
7 changed files with 234 additions and 12 deletions

View File

@ -138,6 +138,7 @@
<activity
android:name=".activity.setup.AccountSettingsXL"
android:label="@string/account_settings_action"
android:theme="@android:style/Theme.WithActionBar" >
>
</activity>
<activity

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/add_new_account"
android:title="@string/add_account_action"
android:icon="@android:drawable/ic_menu_add"
android:showAsAction="ifRoom"
/>
</menu>

View File

@ -640,7 +640,13 @@
<!-- Title of Remove account confirmation dialog box -->
<string name="account_delete_dlg_title">Remove account</string>
<!-- Message of Remove account confirmation dialog box -->
<string name="account_delete_dlg_instructions_fmt">The account \"<xliff:g id="account">%s</xliff:g>\" will be removed from Email.</string>
<string name="account_delete_dlg_instructions_fmt">
The account \"<xliff:g id="account">%s</xliff:g>\" will be removed from Email.</string>
<!-- On Settings screen, section heading for delete account [CHAR LIMIT=none] -->
<string name="account_settings_category_delete_account">Remove account</string>
<!-- On Settings screen, settings option for delete account [CHAR LIMIT=none] -->
<string name="account_settings_delete_account_label">Remove account</string>
<!-- Title of Upgrade Accounts activity -->
<string name="upgrade_accounts_title">Upgrade accounts</string>

View File

@ -119,4 +119,13 @@
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">
<PreferenceScreen
android:key="delete_account"
android:title="@string/account_settings_delete_account_label" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -164,6 +164,16 @@ public class AccountSettings extends Activity
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)

View File

@ -16,19 +16,29 @@
package com.android.email.activity.setup;
import com.android.email.Controller;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.AccountFolderList;
import com.android.email.activity.setup.AccountSetupBasicsFragment.NoteDialogFragment;
import com.android.email.mail.MessagingException;
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.HostAuth;
import com.android.email.service.MailService;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
@ -51,6 +61,8 @@ import android.util.Log;
* TODO: Can we defer calling addPreferencesFromResource() until after we load the account? This
* could reduce flicker.
*
* STOPSHIP: Find a permanent home for delete account
*
* STOPSHIP: Remove fragment lifecycle logging
*/
public class AccountSettingsFragment extends PreferenceFragment {
@ -67,11 +79,13 @@ public class AccountSettingsFragment extends PreferenceFragment {
private static final String PREFERENCE_NOTIFY = "account_notify";
private static final String PREFERENCE_VIBRATE_WHEN = "account_settings_vibrate_when";
private static final String PREFERENCE_RINGTONE = "account_ringtone";
private static final String PREFERENCE_SERVER_CATERGORY = "account_servers";
private static final String PREFERENCE_SERVER_CATEGORY = "account_servers";
private static final String PREFERENCE_INCOMING = "incoming";
private static final String PREFERENCE_OUTGOING = "outgoing";
private static final String PREFERENCE_SYNC_CONTACTS = "account_sync_contacts";
private static final String PREFERENCE_SYNC_CALENDAR = "account_sync_calendar";
private static final String PREFERENCE_DELETE_ACCOUNT_CATEGORY = "category_delete_account";
private static final String PREFERENCE_DELETE_ACCOUNT = "delete_account";
// These strings must match account_settings_vibrate_when_* strings in strings.xml
private static final String PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS = "always";
@ -108,6 +122,7 @@ public class AccountSettingsFragment extends PreferenceFragment {
public void onIncomingSettings(Account account);
public void onOutgoingSettings(Account account);
public void abandonEdit();
public void deleteAccount(Account account);
}
private static class EmptyCallback implements Callback {
@ -115,6 +130,7 @@ public class AccountSettingsFragment extends PreferenceFragment {
@Override public void onIncomingSettings(Account account) { }
@Override public void onOutgoingSettings(Account account) { }
@Override public void abandonEdit() { }
@Override public void deleteAccount(Account account) { };
}
/**
@ -484,7 +500,7 @@ public class AccountSettingsFragment extends PreferenceFragment {
});
} else {
PreferenceCategory serverCategory = (PreferenceCategory) findPreference(
PREFERENCE_SERVER_CATERGORY);
PREFERENCE_SERVER_CATEGORY);
serverCategory.removePreference(prefOutgoing);
}
@ -499,10 +515,22 @@ public class AccountSettingsFragment extends PreferenceFragment {
.getSyncAutomatically(acct, Calendar.AUTHORITY));
} else {
PreferenceCategory serverCategory = (PreferenceCategory) findPreference(
PREFERENCE_SERVER_CATERGORY);
PREFERENCE_SERVER_CATEGORY);
serverCategory.removePreference(mSyncContacts);
serverCategory.removePreference(mSyncCalendar);
}
// Temporary home for delete account
Preference prefDeleteAccount = findPreference(PREFERENCE_DELETE_ACCOUNT);
prefDeleteAccount.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
DeleteAccountFragment dialogFragment = DeleteAccountFragment.newInstance(
mAccount, AccountSettingsFragment.this);
dialogFragment.show(getActivity(), DeleteAccountFragment.TAG);
return true;
}
});
}
/*
@ -544,4 +572,64 @@ public class AccountSettingsFragment extends PreferenceFragment {
AccountSettingsUtils.commitSettings(mContext, mAccount);
Email.setServicesEnabled(mContext);
}
/**
* Dialog fragment to show "remove account?" dialog
*/
public static class DeleteAccountFragment extends DialogFragment {
private final static String TAG = "DeleteAccountFragment";
// Argument bundle keys
private final static String BUNDLE_KEY_ACCOUNT_NAME = "DeleteAccountFragment.Name";
/**
* Create the dialog with parameters
*/
public static DeleteAccountFragment newInstance(Account account, Fragment parentFragment) {
DeleteAccountFragment f = new DeleteAccountFragment();
Bundle b = new Bundle();
b.putString(BUNDLE_KEY_ACCOUNT_NAME, account.getDisplayName());
f.setArguments(b);
f.setTargetFragment(parentFragment, 0);
return f;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
final String name = getArguments().getString(BUNDLE_KEY_ACCOUNT_NAME);
return new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.account_delete_dlg_title)
.setMessage(context.getString(R.string.account_delete_dlg_instructions_fmt, name))
.setPositiveButton(
R.string.okay_action,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Fragment f = getTargetFragment();
if (f instanceof AccountSettingsFragment) {
((AccountSettingsFragment)f).finishDeleteAccount();
}
dismiss();
}
})
.setNegativeButton(
R.string.cancel_action,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dismiss();
}
})
.create();
}
}
/**
* Callback from delete account dialog - passes the delete command up to the activity
*/
private void finishDeleteAccount() {
mSaveOnExit = false;
mCallback.deleteAccount(mAccount);
}
}

View File

@ -33,6 +33,8 @@ import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import java.util.List;
@ -42,11 +44,10 @@ import java.util.List;
* 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: Action bar? Need to work out the handling of next/back type buttons
* TODO: Rework all remaining calls to DB from UI thread
* TODO: Handle dynamic changes to the account list (exit if necessary)
* TODO: Add account
* TODO: Delete account
* TODO: Clean up show/hide icon for add account
* TODO: Finish delete account
*/
public class AccountSettingsXL extends PreferenceActivity
implements AccountSettingsFragment.OnAttachListener {
@ -58,6 +59,7 @@ public class AccountSettingsXL extends PreferenceActivity
private Header mAppPreferencesHeader;
private int mCurrentHeaderPosition;
private Fragment mCurrentFragment;
private long mDeletingAccountId = -1;
// Async Tasks
private LoadAccountListTask mLoadAccountListTask;
@ -100,13 +102,65 @@ public class AccountSettingsXL extends PreferenceActivity
mLoadAccountListTask = null;
}
/**
* Only show "add account" when header showing and not in a sub-fragment (like incoming)
*
* TODO: it might make more sense to do this by having fragments add the items, except for
* this problem: How do we add items that are shown in single pane headers-only mode?
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
if (shouldShowNewAccount()) {
getMenuInflater().inflate(R.menu.account_settings_option, menu);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_new_account:
onAddNewAccount();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/**
* Decide if "add account" should be shown
*
* TODO: it might make more sense to do this by having fragments add the items, except for
* this problem: How do we add items that are shown in single pane headers-only mode?
*/
private boolean shouldShowNewAccount() {
// If in single pane mode, only add accounts at top level
if (!isMultiPane()) {
if (!hasHeaders()) return false;
} else {
// If in multi pane mode, only add accounts when showing a top level fragment
// Note: null is OK; This is the case when we first launch the activity
if ((mCurrentFragment != null)
&& !(mCurrentFragment instanceof AccountSettingsFragment)
&& !(mCurrentFragment instanceof AccountSettingsFragment)) return false;
}
return true;
}
private void onAddNewAccount() {
AccountSetupBasics.actionNewAccount(this);
}
/**
* Start the async reload of the accounts list (if the headers are being displayed)
*/
private void updateAccounts() {
if (hasHeaders()) {
Utility.cancelTaskInterrupt(mLoadAccountListTask);
mLoadAccountListTask = (LoadAccountListTask) new LoadAccountListTask().execute();
mLoadAccountListTask = (LoadAccountListTask)
new LoadAccountListTask().execute(mDeletingAccountId);
}
}
@ -141,12 +195,14 @@ public class AccountSettingsXL extends PreferenceActivity
*
* TODO: Smaller projection
* TODO: Convert to Loader
* TODO: Write a test, including operation of deletingAccountId param
*/
private class LoadAccountListTask extends AsyncTask<Void, Void, Header[]> {
private class LoadAccountListTask extends AsyncTask<Long, Void, Header[]> {
@Override
protected Header[] doInBackground(Void... params) {
protected Header[] doInBackground(Long... params) {
Header[] result = null;
long deletingAccountId = params[0];
Cursor c = getContentResolver().query(
EmailContent.Account.CONTENT_URI,
@ -157,14 +213,18 @@ public class AccountSettingsXL extends PreferenceActivity
result = new Header[headerCount];
while (c.moveToNext()) {
long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
if (accountId == deletingAccountId) {
continue;
}
String title = c.getString(Account.CONTENT_DISPLAY_NAME_COLUMN);
String summary = c.getString(Account.CONTENT_EMAIL_ADDRESS_COLUMN);
long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
Header newHeader = new Header();
newHeader.title = title;
newHeader.summary = summary;
newHeader.fragment = AccountSettingsFragment.class.getCanonicalName();
newHeader.fragmentArguments = AccountSettingsFragment.buildArguments(accountId);
newHeader.fragmentArguments =
AccountSettingsFragment.buildArguments(accountId);
result[index++] = newHeader;
}
} finally {
@ -177,6 +237,8 @@ public class AccountSettingsXL extends PreferenceActivity
@Override
protected void onPostExecute(Header[] headers) {
if (this.isCancelled()) return;
// report the settings
mAccountListHeaders = headers;
AccountSettingsXL.this.invalidateHeaders();
}
@ -213,6 +275,8 @@ public class AccountSettingsXL extends PreferenceActivity
} else if (f instanceof AccountSetupExchangeFragment) {
// TODO
}
// Since we're changing fragments, reset the options menu (not all choices are shown)
invalidateOptionsMenu();
}
/**
@ -228,6 +292,9 @@ public class AccountSettingsXL extends PreferenceActivity
public void abandonEdit() {
finish();
}
public void deleteAccount(Account account) {
AccountSettingsXL.this.deleteAccount(account);
}
}
/**
@ -268,6 +335,24 @@ public class AccountSettingsXL extends PreferenceActivity
}
}
/**
* Delete the selected account
*/
public void deleteAccount(Account account) {
Utility.showToast(this, "Pretend to delete " + account.getDisplayName());
// Kick off the work to delete the account
// TODO copy this logic from AccountFolderList
// If single pane, return to the header list. If multi, rebuild header list
if (isMultiPane()) {
mDeletingAccountId = account.mId;
invalidateHeaders();
} else {
// We should only be calling this while showing AccountSettingsFragment,
// so a finish() should bring us back to headers. No point hiding the deleted account.
finish();
}
}
/**
* Placeholder for app-wide preferences
* STOPSHIP - make this real