| /* |
| * 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.app.Activity; |
| import android.app.LoaderManager; |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| import android.content.Context; |
| 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.Bundle; |
| 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.view.Menu; |
| import android.view.MenuInflater; |
| |
| 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.mail.preferences.AccountPreferences; |
| import com.android.mail.preferences.FolderPreferences; |
| 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.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.HashMap; |
| 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 = "account_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_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; |
| |
| 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 Context mContext; |
| |
| private Account mAccount; |
| private com.android.mail.providers.Account mUiAccount; |
| private EmailServiceInfo mServiceInfo; |
| private Folder mInboxFolder; |
| |
| private Ringtone mRingtone; |
| |
| /** |
| * 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); |
| |
| 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); |
| if (mCheckFrequency != null) { |
| mCheckFrequency.setEntries(syncIntervalStrings); |
| mCheckFrequency.setEntryValues(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)) { |
| startActivity(MailboxSettings.getIntent(getActivity(), mUiAccount.fullFolderListUri, |
| mInboxFolder)); |
| 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. Leave the current sync frequency |
| // in the database. |
| 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_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(); |
| inflater.inflate(R.menu.settings_fragment_menu, menu); |
| } |
| |
| /** |
| * 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); |
| mCheckFrequency.setEntries(mServiceInfo.syncIntervalStrings); |
| mCheckFrequency.setEntryValues(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) { |
| 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; |
| } |
| } |
| } 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); |
| } |
| } |