replicant-packages_apps_Email/src/com/android/email/activity/setup/AccountSettingsFragment.java

1208 lines
54 KiB
Java

/*
* 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.
*/
package com.android.email.activity.setup;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.LoaderManager;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.os.Vibrator;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Window;
import android.widget.Toast;
import com.android.email.R;
import com.android.email.SecurityPolicy;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.FolderPickerActivity;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.mail.preferences.AccountPreferences;
import com.android.mail.preferences.FolderPreferences;
import com.android.mail.preferences.FolderPreferences.NotificationLight;
import com.android.mail.preferences.notifications.FolderNotificationLightPreference;
import com.android.mail.providers.Folder;
import com.android.mail.providers.UIProvider;
import com.android.mail.ui.MailAsyncTaskLoader;
import com.android.mail.ui.settings.MailAccountPrefsFragment;
import com.android.mail.ui.settings.PublicPreferenceActivity;
import com.android.mail.ui.settings.SettingsUtils;
import com.android.mail.utils.ContentProviderTask.UpdateTask;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.NotificationUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Fragment containing the main logic for account settings. This also calls out to other
* fragments for server settings.
*
* TODO: Can we defer calling addPreferencesFromResource() until after we load the account? This
* could reduce flicker.
*/
public class AccountSettingsFragment extends MailAccountPrefsFragment
implements Preference.OnPreferenceChangeListener {
private static final String ARG_ACCOUNT_ID = "account_id";
public static final String PREFERENCE_DESCRIPTION = "account_description";
private static final String PREFERENCE_NAME = "account_name";
private static final String PREFERENCE_SIGNATURE = "account_signature";
private static final String PREFERENCE_QUICK_RESPONSES = "account_quick_responses";
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
private static final String PREFERENCE_SYNC_WINDOW = "account_sync_window";
private static final String PREFERENCE_SYNC_SETTINGS = MailboxSettings.PREFERENCE_SYNC_SETTINGS;
private static final String PREFERENCE_SYNC_EMAIL = "account_sync_email";
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_BACKGROUND_ATTACHMENTS =
"account_background_attachments";
private static final String PREFERENCE_PER_FOLDER_NOTIFICATIONS =
MailboxSettings.PREFERENCE_PER_FOLDER_NOTIFICATIONS;
private static final String PREFERENCE_CATEGORY_DATA_USAGE = "data_usage";
private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "account_notifications";
private static final String PREFERENCE_CATEGORY_SERVER = "account_servers";
private static final String PREFERENCE_CATEGORY_POLICIES = "account_policies";
@SuppressWarnings("unused") // temporarily unused pending policy UI
private static final String PREFERENCE_POLICIES_ENFORCED = "policies_enforced";
@SuppressWarnings("unused") // temporarily unused pending policy UI
private static final String PREFERENCE_POLICIES_UNSUPPORTED = "policies_unsupported";
private static final String PREFERENCE_POLICIES_RETRY_ACCOUNT = "policies_retry_account";
private static final String PREFERENCE_INCOMING = "incoming";
private static final String PREFERENCE_OUTGOING = "outgoing";
private static final String PREFERENCE_SYSTEM_FOLDERS = "system_folders";
private static final String PREFERENCE_SYSTEM_FOLDERS_TRASH = "system_folders_trash";
private static final String PREFERENCE_SYSTEM_FOLDERS_SENT = "system_folders_sent";
private static final String SAVESTATE_SYNC_INTERVALS = "savestate_sync_intervals";
private static final String SAVESTATE_SYNC_INTERVAL_STRINGS = "savestate_sync_interval_strings";
// Request code to start different activities.
private static final int RINGTONE_REQUEST_CODE = 0;
// Message codes
private static final int MSG_DELETE_ACCOUNT = 0;
private EditTextPreference mAccountDescription;
private EditTextPreference mAccountName;
private EditTextPreference mAccountSignature;
private ListPreference mCheckFrequency;
private ListPreference mSyncWindow;
private Preference mSyncSettings;
private CheckBoxPreference mInboxVibrate;
private Preference mInboxRingtone;
private FolderNotificationLightPreference mInboxLights;
private Preference mPerFolderNotification;
private Context mContext;
private Handler mHandler;
private Account mAccount;
private com.android.mail.providers.Account mUiAccount;
private EmailServiceInfo mServiceInfo;
private Folder mInboxFolder;
private Ringtone mRingtone;
private MenuItem mDeleteAccountItem;
private final Callback mHandlerCallback = new Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_DELETE_ACCOUNT) {
deleteAccount();
}
return false;
}
};
/**
* This may be null if the account exists but the inbox has not yet been created in the database
* (waiting for initial sync)
*/
private FolderPreferences mInboxFolderPreferences;
// The email of the account being edited
private String mAccountEmail;
/**
* If launching with an email address, use this method to build the arguments.
*/
public static Bundle buildArguments(final String email) {
final Bundle b = new Bundle(1);
b.putString(ARG_ACCOUNT_EMAIL, email);
return b;
}
/**
* If launching with an account ID, use this method to build the arguments.
*/
public static Bundle buildArguments(final long accountId) {
final Bundle b = new Bundle(1);
b.putLong(ARG_ACCOUNT_ID, accountId);
return b;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity;
}
/**
* Called to do initial creation of a fragment. This is called after
* {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler(mHandlerCallback);
setHasOptionsMenu(true);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.account_settings_preferences);
if (!getResources().getBoolean(R.bool.quickresponse_supported)) {
final Preference quickResponsePref = findPreference(PREFERENCE_QUICK_RESPONSES);
if (quickResponsePref != null) {
getPreferenceScreen().removePreference(quickResponsePref);
}
}
// Start loading the account data, if provided in the arguments
// If not, activity must call startLoadingAccount() directly
Bundle b = getArguments();
if (b != null) {
mAccountEmail = b.getString(ARG_ACCOUNT_EMAIL);
}
if (savedInstanceState != null) {
// We won't know what the correct set of sync interval values and strings are until
// our loader completes. The problem is, that if the sync frequency chooser is
// displayed when the screen rotates, it reinitializes it to the defaults, and doesn't
// correct it after the loader finishes again. See b/13624066
// To work around this, we'll save the current set of sync interval values and strings,
// in onSavedInstanceState, and restore them here.
final CharSequence [] syncIntervalStrings =
savedInstanceState.getCharSequenceArray(SAVESTATE_SYNC_INTERVAL_STRINGS);
final CharSequence [] syncIntervals =
savedInstanceState.getCharSequenceArray(SAVESTATE_SYNC_INTERVALS);
mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
fillCheckFrecuency(syncIntervalStrings, syncIntervals);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outstate) {
super.onSaveInstanceState(outstate);
if (mCheckFrequency != null) {
outstate.putCharSequenceArray(SAVESTATE_SYNC_INTERVAL_STRINGS,
mCheckFrequency.getEntries());
outstate.putCharSequenceArray(SAVESTATE_SYNC_INTERVALS,
mCheckFrequency.getEntryValues());
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Bundle args = new Bundle(1);
if (!TextUtils.isEmpty(mAccountEmail)) {
args.putString(AccountLoaderCallbacks.ARG_ACCOUNT_EMAIL, mAccountEmail);
} else {
args.putLong(AccountLoaderCallbacks.ARG_ACCOUNT_ID,
getArguments().getLong(ARG_ACCOUNT_ID, -1));
}
getLoaderManager().initLoader(0, args, new AccountLoaderCallbacks(getActivity()));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case RINGTONE_REQUEST_CODE:
if (resultCode == Activity.RESULT_OK && data != null) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
setRingtone(uri);
}
break;
}
}
/**
* Sets the current ringtone.
*/
private void setRingtone(Uri ringtone) {
if (ringtone != null) {
mInboxFolderPreferences.setNotificationRingtoneUri(ringtone.toString());
mRingtone = RingtoneManager.getRingtone(getActivity(), ringtone);
} else {
// Null means silent was selected.
mInboxFolderPreferences.setNotificationRingtoneUri("");
mRingtone = null;
}
setRingtoneSummary();
}
private void setRingtoneSummary() {
final String summary = mRingtone != null ? mRingtone.getTitle(mContext)
: mContext.getString(R.string.silent_ringtone);
mInboxRingtone.setSummary(summary);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
@NonNull Preference preference) {
final String key = preference.getKey();
if (key.equals(PREFERENCE_SYNC_SETTINGS) ||
key.equals(PREFERENCE_PER_FOLDER_NOTIFICATIONS)) {
startActivity(MailboxSettings.getIntent(getActivity(), mUiAccount.fullFolderListUri,
mInboxFolder, key));
return true;
} else {
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
}
/**
* Listen to all preference changes in this class.
* @param preference The changed Preference
* @param newValue The new value of the Preference
* @return True to update the state of the Preference with the new value
*/
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Can't use a switch here. Falling back to a giant conditional.
final String key = preference.getKey();
final ContentValues cv = new ContentValues(1);
if (key.equals(PREFERENCE_DESCRIPTION)){
String summary = newValue.toString().trim();
if (TextUtils.isEmpty(summary)) {
summary = mUiAccount.getEmailAddress();
}
mAccountDescription.setSummary(summary);
mAccountDescription.setText(summary);
cv.put(AccountColumns.DISPLAY_NAME, summary);
} else if (key.equals(PREFERENCE_NAME)) {
final String summary = newValue.toString().trim();
if (!TextUtils.isEmpty(summary)) {
mAccountName.setSummary(summary);
mAccountName.setText(summary);
cv.put(AccountColumns.SENDER_NAME, summary);
}
} else if (key.equals(PREFERENCE_SIGNATURE)) {
// Clean up signature if it's only whitespace (which is easy to do on a
// soft keyboard) but leave whitespace in place otherwise, to give the user
// maximum flexibility, e.g. the ability to indent
String signature = newValue.toString();
if (signature.trim().isEmpty()) {
signature = "";
}
mAccountSignature.setText(signature);
SettingsUtils.updatePreferenceSummary(mAccountSignature, signature,
R.string.preferences_signature_summary_not_set);
cv.put(AccountColumns.SIGNATURE, signature);
} else if (key.equals(PREFERENCE_FREQUENCY)) {
final String summary = newValue.toString();
final int index = mCheckFrequency.findIndexOfValue(summary);
mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]);
mCheckFrequency.setValue(summary);
if (mServiceInfo.syncContacts || mServiceInfo.syncCalendar) {
// This account allows syncing of contacts and/or calendar, so we will always have
// separate preferences to enable or disable syncing of email, contacts, and
// calendar.
// The "sync frequency" preference really just needs to control the frequency value
// in our database.
cv.put(AccountColumns.SYNC_INTERVAL, Integer.parseInt(summary));
} else {
// This account only syncs email (not contacts or calendar), which means that we
// will hide the preference to turn syncing on and off. In this case, we want the
// sync frequency preference to also control whether or not syncing is enabled at
// all. If sync is turned off, we will display "sync never" regardless of what the
// numeric value we have stored says.
final android.accounts.Account androidAcct = new android.accounts.Account(
mAccount.mEmailAddress, mServiceInfo.accountType);
if (Integer.parseInt(summary) == Account.CHECK_INTERVAL_NEVER) {
// Disable syncing from the account manager.
ContentResolver.setSyncAutomatically(androidAcct, EmailContent.AUTHORITY,
false);
} else {
// Enable syncing from the account manager.
ContentResolver.setSyncAutomatically(androidAcct, EmailContent.AUTHORITY,
true);
}
cv.put(AccountColumns.SYNC_INTERVAL, Integer.parseInt(summary));
}
} else if (key.equals(PREFERENCE_SYNC_WINDOW)) {
final String summary = newValue.toString();
int index = mSyncWindow.findIndexOfValue(summary);
mSyncWindow.setSummary(mSyncWindow.getEntries()[index]);
mSyncWindow.setValue(summary);
cv.put(AccountColumns.SYNC_LOOKBACK, Integer.parseInt(summary));
} else if (key.equals(PREFERENCE_SYNC_EMAIL)) {
final android.accounts.Account androidAcct = new android.accounts.Account(
mAccount.mEmailAddress, mServiceInfo.accountType);
ContentResolver.setSyncAutomatically(androidAcct, EmailContent.AUTHORITY,
(Boolean) newValue);
loadSettings();
} else if (key.equals(PREFERENCE_SYNC_CONTACTS)) {
final android.accounts.Account androidAcct = new android.accounts.Account(
mAccount.mEmailAddress, mServiceInfo.accountType);
ContentResolver.setSyncAutomatically(androidAcct, ContactsContract.AUTHORITY,
(Boolean) newValue);
loadSettings();
} else if (key.equals(PREFERENCE_SYNC_CALENDAR)) {
final android.accounts.Account androidAcct = new android.accounts.Account(
mAccount.mEmailAddress, mServiceInfo.accountType);
ContentResolver.setSyncAutomatically(androidAcct, CalendarContract.AUTHORITY,
(Boolean) newValue);
loadSettings();
} else if (key.equals(PREFERENCE_BACKGROUND_ATTACHMENTS)) {
int newFlags = mAccount.getFlags() & ~(Account.FLAGS_BACKGROUND_ATTACHMENTS);
newFlags |= (Boolean) newValue ?
Account.FLAGS_BACKGROUND_ATTACHMENTS : 0;
cv.put(AccountColumns.FLAGS, newFlags);
} else if (FolderPreferences.PreferenceKeys.NOTIFICATIONS_ENABLED.equals(key)) {
mInboxFolderPreferences.setNotificationsEnabled((Boolean) newValue);
return true;
} else if (FolderPreferences.PreferenceKeys.NOTIFICATION_VIBRATE.equals(key)) {
final boolean vibrateSetting = (Boolean) newValue;
mInboxVibrate.setChecked(vibrateSetting);
mInboxFolderPreferences.setNotificationVibrateEnabled(vibrateSetting);
return true;
} else if (FolderPreferences.PreferenceKeys.NOTIFICATION_LIGHTS.equals(key)) {
final String LightsSettings = (String) newValue;
NotificationLight notificationLight = NotificationLight.fromStringPref(LightsSettings);
updateNotificationLight(notificationLight);
mInboxFolderPreferences.setNotificationLights(notificationLight);
return true;
} else if (FolderPreferences.PreferenceKeys.NOTIFICATION_RINGTONE.equals(key)) {
return true;
} else {
// Default behavior, just indicate that the preferences were written
LogUtils.d(LogUtils.TAG, "Unknown preference key %s", key);
return true;
}
if (cv.size() > 0) {
new UpdateTask().run(mContext.getContentResolver(), mAccount.getUri(), cv, null, null);
EmailProvider.setServicesEnabledAsync(mContext);
}
return false;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
// Delete account item
mDeleteAccountItem = menu.add(Menu.NONE, Menu.NONE, 0, R.string.delete_account);
mDeleteAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
inflater.inflate(R.menu.settings_fragment_menu, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.equals(mDeleteAccountItem)) {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(mContext);
alertBuilder.setTitle(R.string.delete_account);
String msg = getString(R.string.delete_account_confirmation_msg, mAccountEmail);
alertBuilder.setMessage(msg);
alertBuilder.setCancelable(true);
final DialogInterface.OnClickListener cb = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mHandler.dispatchMessage(Message.obtain(mHandler, MSG_DELETE_ACCOUNT));
}
};
alertBuilder.setPositiveButton(android.R.string.ok, cb);
alertBuilder.setNegativeButton(android.R.string.cancel, null);
alertBuilder.create().show();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Async task loader to load account in order to view/edit it
*/
private static class AccountLoader extends MailAsyncTaskLoader<Map<String, Object>> {
public static final String RESULT_KEY_ACCOUNT = "account";
private static final String RESULT_KEY_UIACCOUNT_CURSOR = "uiAccountCursor";
public static final String RESULT_KEY_UIACCOUNT = "uiAccount";
public static final String RESULT_KEY_INBOX = "inbox";
private final ForceLoadContentObserver mObserver;
private final String mAccountEmail;
private final long mAccountId;
private AccountLoader(Context context, String accountEmail, long accountId) {
super(context);
mObserver = new ForceLoadContentObserver();
mAccountEmail = accountEmail;
mAccountId = accountId;
}
@Override
public Map<String, Object> loadInBackground() {
final Map<String, Object> map = new HashMap<>();
final Account account;
if (!TextUtils.isEmpty(mAccountEmail)) {
account = Account.restoreAccountWithAddress(getContext(), mAccountEmail, mObserver);
} else {
account = Account.restoreAccountWithId(getContext(), mAccountId, mObserver);
}
if (account == null) {
return map;
}
map.put(RESULT_KEY_ACCOUNT, account);
// We don't monitor these for changes, but they probably won't change in any meaningful
// way
account.getOrCreateHostAuthRecv(getContext());
account.getOrCreateHostAuthSend(getContext());
if (account.mHostAuthRecv == null) {
return map;
}
account.mPolicy =
Policy.restorePolicyWithId(getContext(), account.mPolicyKey, mObserver);
final Cursor uiAccountCursor = getContext().getContentResolver().query(
EmailProvider.uiUri("uiaccount", account.getId()),
UIProvider.ACCOUNTS_PROJECTION,
null, null, null);
if (uiAccountCursor != null) {
map.put(RESULT_KEY_UIACCOUNT_CURSOR, uiAccountCursor);
uiAccountCursor.registerContentObserver(mObserver);
} else {
return map;
}
if (!uiAccountCursor.moveToFirst()) {
return map;
}
final com.android.mail.providers.Account uiAccount =
com.android.mail.providers.Account.builder().buildFrom(uiAccountCursor);
map.put(RESULT_KEY_UIACCOUNT, uiAccount);
final Cursor folderCursor = getContext().getContentResolver().query(
uiAccount.settings.defaultInbox, UIProvider.FOLDERS_PROJECTION, null, null,
null);
final Folder inbox;
try {
if (folderCursor != null && folderCursor.moveToFirst()) {
inbox = new Folder(folderCursor);
} else {
return map;
}
} finally {
if (folderCursor != null) {
folderCursor.close();
}
}
map.put(RESULT_KEY_INBOX, inbox);
return map;
}
@Override
protected void onDiscardResult(Map<String, Object> result) {
final Account account = (Account) result.get(RESULT_KEY_ACCOUNT);
if (account != null) {
if (account.mPolicy != null) {
account.mPolicy.close(getContext());
}
account.close(getContext());
}
final Cursor uiAccountCursor = (Cursor) result.get(RESULT_KEY_UIACCOUNT_CURSOR);
if (uiAccountCursor != null) {
uiAccountCursor.close();
}
}
}
private class AccountLoaderCallbacks
implements LoaderManager.LoaderCallbacks<Map<String, Object>> {
public static final String ARG_ACCOUNT_EMAIL = "accountEmail";
public static final String ARG_ACCOUNT_ID = "accountId";
private final Context mContext;
private AccountLoaderCallbacks(Context context) {
mContext = context;
}
@Override
public void onLoadFinished(Loader<Map<String, Object>> loader, Map<String, Object> data) {
final Activity activity = getActivity();
if (activity == null) {
return;
}
if (data == null) {
activity.finish();
return;
}
mUiAccount = (com.android.mail.providers.Account)
data.get(AccountLoader.RESULT_KEY_UIACCOUNT);
mAccount = (Account) data.get(AccountLoader.RESULT_KEY_ACCOUNT);
if (mAccount != null && (mAccount.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
final Intent i = AccountSecurity.actionUpdateSecurityIntent(mContext,
mAccount.getId(), true);
mContext.startActivity(i);
activity.finish();
return;
}
mInboxFolder = (Folder) data.get(AccountLoader.RESULT_KEY_INBOX);
if (mUiAccount == null || mAccount == null) {
activity.finish();
return;
}
mServiceInfo =
EmailServiceUtils.getServiceInfo(mContext, mAccount.getProtocol(mContext));
if (mInboxFolder == null) {
mInboxFolderPreferences = null;
} else {
mInboxFolderPreferences = new FolderPreferences(mContext,
mUiAccount.getEmailAddress(), mInboxFolder, true);
}
loadSettings();
}
@Override
public Loader<Map<String, Object>> onCreateLoader(int id, Bundle args) {
return new AccountLoader(mContext, args.getString(ARG_ACCOUNT_EMAIL),
args.getLong(ARG_ACCOUNT_ID));
}
@Override
public void onLoaderReset(Loader<Map<String, Object>> loader) {}
}
/**
* From a Policy, create and return an ArrayList of Strings that describe (simply) those
* policies that are supported by the OS. At the moment, the strings are simple (e.g.
* "password required"); we should probably add more information (# characters, etc.), though
*/
@SuppressWarnings("unused") // temporarily unused pending policy UI
private ArrayList<String> getSystemPoliciesList(Policy policy) {
Resources res = mContext.getResources();
ArrayList<String> policies = new ArrayList<>();
if (policy.mPasswordMode != Policy.PASSWORD_MODE_NONE) {
policies.add(res.getString(R.string.policy_require_password));
}
if (policy.mPasswordHistory > 0) {
policies.add(res.getString(R.string.policy_password_history));
}
if (policy.mPasswordExpirationDays > 0) {
policies.add(res.getString(R.string.policy_password_expiration));
}
if (policy.mMaxScreenLockTime > 0) {
policies.add(res.getString(R.string.policy_screen_timeout));
}
if (policy.mDontAllowCamera) {
policies.add(res.getString(R.string.policy_dont_allow_camera));
}
if (policy.mMaxEmailLookback != 0) {
policies.add(res.getString(R.string.policy_email_age));
}
if (policy.mMaxCalendarLookback != 0) {
policies.add(res.getString(R.string.policy_calendar_age));
}
return policies;
}
@SuppressWarnings("unused") // temporarily unused pending policy UI
private void setPolicyListSummary(ArrayList<String> policies, String policiesToAdd,
String preferenceName) {
Policy.addPolicyStringToList(policiesToAdd, policies);
if (policies.size() > 0) {
Preference p = findPreference(preferenceName);
StringBuilder sb = new StringBuilder();
for (String desc: policies) {
sb.append(desc);
sb.append('\n');
}
p.setSummary(sb.toString());
}
}
/**
* Load account data into preference UI. This must be called on the main thread.
*/
private void loadSettings() {
final AccountPreferences accountPreferences =
new AccountPreferences(mContext, mUiAccount.getEmailAddress());
if (mInboxFolderPreferences != null) {
NotificationUtils.moveNotificationSetting(
accountPreferences, mInboxFolderPreferences);
}
final String protocol = mAccount.getProtocol(mContext);
if (mServiceInfo == null) {
LogUtils.e(LogUtils.TAG,
"Could not find service info for account %d with protocol %s", mAccount.mId,
protocol);
getActivity().onBackPressed();
// TODO: put up some sort of dialog/toast here to tell the user something went wrong
return;
}
final android.accounts.Account androidAcct = mUiAccount.getAccountManagerAccount();
mAccountDescription = (EditTextPreference) findPreference(PREFERENCE_DESCRIPTION);
mAccountDescription.setSummary(mAccount.getDisplayName());
mAccountDescription.setText(mAccount.getDisplayName());
mAccountDescription.setOnPreferenceChangeListener(this);
mAccountName = (EditTextPreference) findPreference(PREFERENCE_NAME);
String senderName = mUiAccount.getSenderName();
// In rare cases, sendername will be null; Change this to empty string to avoid NPE's
if (senderName == null) {
senderName = "";
}
mAccountName.setSummary(senderName);
mAccountName.setText(senderName);
mAccountName.setOnPreferenceChangeListener(this);
final String accountSignature = mAccount.getSignature();
mAccountSignature = (EditTextPreference) findPreference(PREFERENCE_SIGNATURE);
mAccountSignature.setText(accountSignature);
mAccountSignature.setOnPreferenceChangeListener(this);
SettingsUtils.updatePreferenceSummary(mAccountSignature, accountSignature,
R.string.preferences_signature_summary_not_set);
mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
fillCheckFrecuency(mServiceInfo.syncIntervalStrings, mServiceInfo.syncIntervals);
if (mServiceInfo.syncContacts || mServiceInfo.syncCalendar) {
// This account allows syncing of contacts and/or calendar, so we will always have
// separate preferences to enable or disable syncing of email, contacts, and calendar.
// The "sync frequency" preference really just needs to control the frequency value
// in our database.
mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval()));
} else {
// This account only syncs email (not contacts or calendar), which means that we will
// hide the preference to turn syncing on and off. In this case, we want the sync
// frequency preference to also control whether or not syncing is enabled at all. If
// sync is turned off, we will display "sync never" regardless of what the numeric
// value we have stored says.
boolean synced = ContentResolver.getSyncAutomatically(androidAcct,
EmailContent.AUTHORITY);
if (synced) {
mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval()));
} else {
mCheckFrequency.setValue(String.valueOf(Account.CHECK_INTERVAL_NEVER));
}
}
mCheckFrequency.setSummary(mCheckFrequency.getEntry());
mCheckFrequency.setOnPreferenceChangeListener(this);
final Preference quickResponsePref = findPreference(PREFERENCE_QUICK_RESPONSES);
if (quickResponsePref != null) {
quickResponsePref.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
onEditQuickResponses(mUiAccount);
return true;
}
});
}
// Add check window preference
final PreferenceCategory dataUsageCategory =
(PreferenceCategory) findPreference(PREFERENCE_CATEGORY_DATA_USAGE);
if (mServiceInfo.offerLookback) {
if (mSyncWindow == null) {
mSyncWindow = new ListPreference(mContext);
mSyncWindow.setKey(PREFERENCE_SYNC_WINDOW);
dataUsageCategory.addPreference(mSyncWindow);
}
mSyncWindow.setTitle(R.string.account_setup_options_mail_window_label);
mSyncWindow.setValue(String.valueOf(mAccount.getSyncLookback()));
final int maxLookback;
if (mAccount.mPolicy != null) {
maxLookback = mAccount.mPolicy.mMaxEmailLookback;
} else {
maxLookback = 0;
}
MailboxSettings.setupLookbackPreferenceOptions(mContext, mSyncWindow, maxLookback,
false);
// Must correspond to the hole in the XML file that's reserved.
mSyncWindow.setOrder(2);
mSyncWindow.setOnPreferenceChangeListener(this);
if (mSyncSettings == null) {
mSyncSettings = new Preference(mContext);
mSyncSettings.setKey(PREFERENCE_SYNC_SETTINGS);
dataUsageCategory.addPreference(mSyncSettings);
}
mSyncSettings.setTitle(R.string.folder_sync_settings_pref_title);
mSyncSettings.setOrder(3);
}
final PreferenceCategory folderPrefs =
(PreferenceCategory) findPreference(PREFERENCE_SYSTEM_FOLDERS);
if (folderPrefs != null) {
if (mServiceInfo.requiresSetup) {
Preference trashPreference = findPreference(PREFERENCE_SYSTEM_FOLDERS_TRASH);
Intent i = new Intent(mContext, FolderPickerActivity.class);
Uri uri = EmailContent.CONTENT_URI.buildUpon().appendQueryParameter(
"account", Long.toString(mAccount.getId())).build();
i.setData(uri);
i.putExtra(FolderPickerActivity.MAILBOX_TYPE_EXTRA, Mailbox.TYPE_TRASH);
trashPreference.setIntent(i);
Preference sentPreference = findPreference(PREFERENCE_SYSTEM_FOLDERS_SENT);
i = new Intent(mContext, FolderPickerActivity.class);
i.setData(uri);
i.putExtra(FolderPickerActivity.MAILBOX_TYPE_EXTRA, Mailbox.TYPE_SENT);
sentPreference.setIntent(i);
} else {
getPreferenceScreen().removePreference(folderPrefs);
}
}
final CheckBoxPreference backgroundAttachments = (CheckBoxPreference)
findPreference(PREFERENCE_BACKGROUND_ATTACHMENTS);
if (backgroundAttachments != null) {
if (!mServiceInfo.offerAttachmentPreload) {
dataUsageCategory.removePreference(backgroundAttachments);
} else {
backgroundAttachments.setChecked(
0 != (mAccount.getFlags() & Account.FLAGS_BACKGROUND_ATTACHMENTS));
backgroundAttachments.setOnPreferenceChangeListener(this);
}
}
final PreferenceCategory notificationsCategory =
(PreferenceCategory) findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS);
if (mInboxFolderPreferences != null) {
if (mServiceInfo.offerLookback) {
// This account supports per-folder notifications
// Enable per-folder notifications preference
if (mPerFolderNotification == null) {
mPerFolderNotification = new Preference(mContext);
mPerFolderNotification.setKey(PREFERENCE_PER_FOLDER_NOTIFICATIONS);
notificationsCategory.addPreference(mPerFolderNotification);
}
mPerFolderNotification.setTitle(R.string.folder_notify_settings_pref_title);
// Remove Inbox per-account preferences
final CheckBoxPreference inboxNotify = (CheckBoxPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATIONS_ENABLED);
if (inboxNotify != null) {
notificationsCategory.removePreference(inboxNotify);
}
mInboxRingtone = findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_RINGTONE);
if (mInboxRingtone != null) {
notificationsCategory.removePreference(mInboxRingtone);
}
mInboxVibrate = (CheckBoxPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_VIBRATE);
if (mInboxVibrate != null) {
notificationsCategory.removePreference(mInboxVibrate);
}
mInboxLights = (FolderNotificationLightPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_LIGHTS);
if (mInboxLights != null) {
notificationsCategory.removePreference(mInboxLights);
}
notificationsCategory.setEnabled(true);
} else {
final CheckBoxPreference inboxNotify = (CheckBoxPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATIONS_ENABLED);
inboxNotify.setChecked(mInboxFolderPreferences.areNotificationsEnabled());
inboxNotify.setOnPreferenceChangeListener(this);
mInboxRingtone = findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_RINGTONE);
final String ringtoneUri = mInboxFolderPreferences.getNotificationRingtoneUri();
if (!TextUtils.isEmpty(ringtoneUri)) {
mRingtone = RingtoneManager.getRingtone(getActivity(), Uri.parse(ringtoneUri));
}
setRingtoneSummary();
mInboxRingtone.setOnPreferenceChangeListener(this);
mInboxRingtone.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
showRingtonePicker();
return true;
}
});
notificationsCategory.setEnabled(true);
// Set the vibrator value, or hide it on devices w/o a vibrator
mInboxVibrate = (CheckBoxPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_VIBRATE);
if (mInboxVibrate != null) {
mInboxVibrate.setChecked(
mInboxFolderPreferences.isNotificationVibrateEnabled());
Vibrator vibrator = (Vibrator) mContext.getSystemService(
Context.VIBRATOR_SERVICE);
if (vibrator.hasVibrator()) {
// When the value is changed, update the setting.
mInboxVibrate.setOnPreferenceChangeListener(this);
} else {
// No vibrator present. Remove the preference altogether.
notificationsCategory.removePreference(mInboxVibrate);
mInboxVibrate = null;
}
}
boolean isArgbNotifColorSupported = getResources().getBoolean(
com.android.internal.R.bool.config_multiColorNotificationLed);
mInboxLights = (FolderNotificationLightPreference) findPreference(
FolderPreferences.PreferenceKeys.NOTIFICATION_LIGHTS);
if (mInboxLights != null) {
if (isArgbNotifColorSupported) {
updateNotificationLight(mInboxFolderPreferences.getNotificationLight());
mInboxLights.setOnPreferenceChangeListener(this);
} else {
notificationsCategory.removePreference(mInboxLights);
}
}
}
} else {
notificationsCategory.setEnabled(false);
}
final Preference retryAccount = findPreference(PREFERENCE_POLICIES_RETRY_ACCOUNT);
final PreferenceCategory policiesCategory = (PreferenceCategory) findPreference(
PREFERENCE_CATEGORY_POLICIES);
if (policiesCategory != null) {
// TODO: This code for showing policies isn't working. For KLP, just don't even bother
// showing this data; we'll fix this later.
/*
if (policy != null) {
if (policy.mProtocolPoliciesEnforced != null) {
ArrayList<String> policies = getSystemPoliciesList(policy);
setPolicyListSummary(policies, policy.mProtocolPoliciesEnforced,
PREFERENCE_POLICIES_ENFORCED);
}
if (policy.mProtocolPoliciesUnsupported != null) {
ArrayList<String> policies = new ArrayList<String>();
setPolicyListSummary(policies, policy.mProtocolPoliciesUnsupported,
PREFERENCE_POLICIES_UNSUPPORTED);
} else {
// Don't show "retry" unless we have unsupported policies
policiesCategory.removePreference(retryAccount);
}
} else {
*/
// Remove the category completely if there are no policies
getPreferenceScreen().removePreference(policiesCategory);
//}
}
if (retryAccount != null) {
retryAccount.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
// Release the account
SecurityPolicy.setAccountHoldFlag(mContext, mAccount, false);
// Remove the preference
if (policiesCategory != null) {
policiesCategory.removePreference(retryAccount);
}
return true;
}
});
}
findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
onIncomingSettings(mAccount);
return true;
}
});
// Hide the outgoing account setup link if it's not activated
final Preference prefOutgoing = findPreference(PREFERENCE_OUTGOING);
if (prefOutgoing != null) {
if (mServiceInfo.usesSmtp && mAccount.mHostAuthSend != null) {
prefOutgoing.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
onOutgoingSettings(mAccount);
return true;
}
});
} else {
if (mServiceInfo.usesSmtp) {
// We really ought to have an outgoing host auth but we don't.
// There's nothing we can do at this point, so just log the error.
LogUtils.e(LogUtils.TAG, "Account %d has a bad outbound hostauth",
mAccount.getId());
}
PreferenceCategory serverCategory = (PreferenceCategory) findPreference(
PREFERENCE_CATEGORY_SERVER);
serverCategory.removePreference(prefOutgoing);
}
}
final CheckBoxPreference syncContacts =
(CheckBoxPreference) findPreference(PREFERENCE_SYNC_CONTACTS);
final CheckBoxPreference syncCalendar =
(CheckBoxPreference) findPreference(PREFERENCE_SYNC_CALENDAR);
final CheckBoxPreference syncEmail =
(CheckBoxPreference) findPreference(PREFERENCE_SYNC_EMAIL);
if (syncContacts != null && syncCalendar != null && syncEmail != null) {
if (mServiceInfo.syncContacts || mServiceInfo.syncCalendar) {
if (mServiceInfo.syncContacts) {
syncContacts.setChecked(ContentResolver
.getSyncAutomatically(androidAcct, ContactsContract.AUTHORITY));
syncContacts.setOnPreferenceChangeListener(this);
} else {
syncContacts.setChecked(false);
syncContacts.setEnabled(false);
}
if (mServiceInfo.syncCalendar) {
syncCalendar.setChecked(ContentResolver
.getSyncAutomatically(androidAcct, CalendarContract.AUTHORITY));
syncCalendar.setOnPreferenceChangeListener(this);
} else {
syncCalendar.setChecked(false);
syncCalendar.setEnabled(false);
}
syncEmail.setChecked(ContentResolver
.getSyncAutomatically(androidAcct, EmailContent.AUTHORITY));
syncEmail.setOnPreferenceChangeListener(this);
} else {
dataUsageCategory.removePreference(syncContacts);
dataUsageCategory.removePreference(syncCalendar);
dataUsageCategory.removePreference(syncEmail);
}
}
}
/**
* Shows the system ringtone picker.
*/
private void showRingtonePicker() {
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
final String ringtoneUri = mInboxFolderPreferences.getNotificationRingtoneUri();
if (!TextUtils.isEmpty(ringtoneUri)) {
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(ringtoneUri));
}
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
Settings.System.DEFAULT_NOTIFICATION_URI);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
startActivityForResult(intent, RINGTONE_REQUEST_CODE);
}
/**
* Dispatch to edit quick responses.
*/
public void onEditQuickResponses(com.android.mail.providers.Account account) {
final Bundle args = AccountSettingsEditQuickResponsesFragment.createArgs(account);
final PreferenceActivity activity = (PreferenceActivity) getActivity();
activity.startPreferencePanel(AccountSettingsEditQuickResponsesFragment.class.getName(),
args, R.string.account_settings_edit_quick_responses_label, null, null, 0);
}
/**
* Dispatch to edit incoming settings.
*/
public void onIncomingSettings(Account account) {
final Intent intent =
AccountServerSettingsActivity.getIntentForIncoming(getActivity(), account);
getActivity().startActivity(intent);
}
/**
* Dispatch to edit outgoing settings.
*/
public void onOutgoingSettings(Account account) {
final Intent intent =
AccountServerSettingsActivity.getIntentForOutgoing(getActivity(), account);
getActivity().startActivity(intent);
}
private void deleteAccount() {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
private ProgressDialog mDialog;
@Override
protected void onPreExecute() {
// Display an alert dialog to advise the user that the operation is in progress
mDialog = new ProgressDialog(mContext);
mDialog.setMessage(mContext.getString(R.string.deleting_account_msg));
mDialog.setCancelable(false);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.show();
}
@Override
protected void onPostExecute(Boolean result) {
if (!result) {
Toast.makeText(mContext, R.string.delete_account_failed,
Toast.LENGTH_SHORT).show();
}
mDialog.dismiss();
}
@Override
protected Boolean doInBackground(Void... params) {
try {
// Retrieve the necessary information
AccountManager accountManager = (AccountManager)mContext.getSystemService(
Context.ACCOUNT_SERVICE);
android.accounts.Account account = mUiAccount.getAccountManagerAccount();
// Remove the email account and its notifications
ContentResolver resolver = mContext.getContentResolver();
int ret = resolver.delete(mUiAccount.uri, null, null);
if (ret <= 0) {
LogUtils.w(LogUtils.TAG, "Failed to delete account %s", mAccountEmail);
return Boolean.FALSE;
}
NotificationUtils.clearAccountNotifications(mContext, account);
// And now we remove the system account that holds the email service
accountManager.removeAccount(account, getActivity(), null, null);
// Finish after account is deleted
getActivity().finish();
} catch (Exception ex) {
LogUtils.w(LogUtils.TAG, ex, "Failed to delete account %s", mAccountEmail);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
};
task.execute();
}
private void updateNotificationLight(NotificationLight notificationLight) {
if (notificationLight.mOn) {
mInboxLights.setColor(notificationLight.mColor);
mInboxLights.setOnOffValue(notificationLight.mTimeOn, notificationLight.mTimeOff);
} else {
int color = mUiAccount != null && mUiAccount.color != 0
? mUiAccount.color
: FolderNotificationLightPreference.DEFAULT_COLOR;
mInboxLights.setColor(color);
mInboxLights.setOnOffValue(FolderNotificationLightPreference.DEFAULT_TIME,
FolderNotificationLightPreference.DEFAULT_TIME);
}
mInboxLights.setOn(notificationLight.mOn);
}
private void fillCheckFrecuency(CharSequence[] labels, CharSequence[] values) {
if (mCheckFrequency == null) {
return;
}
// Check push capability prior to include as an option
if (mAccount != null) {
boolean hasPushCapability = mAccount.hasCapability(EmailServiceProxy.CAPABILITY_PUSH);
List<CharSequence> valuesList = new ArrayList<>(Arrays.asList(values));
int checkIntervalPushPos = valuesList.indexOf(
String.valueOf(Account.CHECK_INTERVAL_PUSH));
if (!hasPushCapability && checkIntervalPushPos != -1) {
List<CharSequence> labelsList = new ArrayList<>(Arrays.asList(labels));
labelsList.remove(checkIntervalPushPos);
valuesList.remove(checkIntervalPushPos);
labels = labelsList.toArray(new CharSequence[labelsList.size()]);
values = valuesList.toArray(new CharSequence[valuesList.size()]);
}
}
mCheckFrequency.setEntries(labels);
mCheckFrequency.setEntryValues(values);
mCheckFrequency.setDefaultValue(values);
}
}