blob: 5f8f1899209e813317b4221c42804f8cf7bdb2a5 [file] [log] [blame]
Andrew Stadler71cc0352010-08-09 10:36:50 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.activity.setup;
18
Andrew Stadler71cc0352010-08-09 10:36:50 -070019import android.app.Activity;
Andrew Stadlera14a24a2010-08-19 16:28:52 -070020import android.app.AlertDialog;
21import android.app.Dialog;
22import android.app.DialogFragment;
Andrew Stadler2ae2a122010-08-18 11:29:46 -070023import android.app.Fragment;
Dianne Hackborna2cc46c2010-09-12 19:38:10 -070024import android.app.FragmentTransaction;
Andrew Stadler71cc0352010-08-09 10:36:50 -070025import android.content.ContentResolver;
Andy Stadler9f7e3982010-12-22 13:55:19 -080026import android.content.ContentValues;
Andrew Stadler71cc0352010-08-09 10:36:50 -070027import android.content.Context;
Andrew Stadlera14a24a2010-08-19 16:28:52 -070028import android.content.DialogInterface;
Andrew Stadler71cc0352010-08-09 10:36:50 -070029import android.content.SharedPreferences;
Andrew Stadler2ae2a122010-08-18 11:29:46 -070030import android.os.AsyncTask;
Andrew Stadler71cc0352010-08-09 10:36:50 -070031import android.os.Bundle;
Andy Stadler9ce244b2010-11-04 21:13:45 -070032import android.os.Vibrator;
Andrew Stadler71cc0352010-08-09 10:36:50 -070033import android.preference.CheckBoxPreference;
34import android.preference.EditTextPreference;
35import android.preference.ListPreference;
36import android.preference.Preference;
37import android.preference.PreferenceCategory;
38import android.preference.PreferenceFragment;
39import android.preference.RingtonePreference;
Andrew Stadler71cc0352010-08-09 10:36:50 -070040import android.provider.ContactsContract;
Andy Stadler373ccb12011-01-20 11:37:39 -080041import android.text.TextUtils;
Andrew Stadler71cc0352010-08-09 10:36:50 -070042import android.util.Log;
43
Marc Blank85e4c102011-06-08 13:50:00 -070044import com.android.email.Email;
45import com.android.email.R;
46import com.android.email.mail.Sender;
47import com.android.emailcommon.AccountManagerTypes;
48import com.android.emailcommon.CalendarProviderStub;
49import com.android.emailcommon.Logging;
50import com.android.emailcommon.mail.MessagingException;
Marc Blankf5418f12011-06-13 15:32:27 -070051import com.android.emailcommon.provider.Account;
Marc Blank85e4c102011-06-08 13:50:00 -070052import com.android.emailcommon.provider.EmailContent;
Marc Blank85e4c102011-06-08 13:50:00 -070053import com.android.emailcommon.provider.HostAuth;
54import com.android.emailcommon.utility.Utility;
55
Andrew Stadler71cc0352010-08-09 10:36:50 -070056/**
57 * Fragment containing the main logic for account settings. This also calls out to other
58 * fragments for server settings.
59 *
Andy Stadler9f7e3982010-12-22 13:55:19 -080060 * TODO: Remove or make async the mAccountDirty reload logic. Probably no longer needed.
Andrew Stadler2ae2a122010-08-18 11:29:46 -070061 * TODO: Can we defer calling addPreferencesFromResource() until after we load the account? This
62 * could reduce flicker.
Andrew Stadler71cc0352010-08-09 10:36:50 -070063 */
64public class AccountSettingsFragment extends PreferenceFragment {
Andrew Stadler2ae2a122010-08-18 11:29:46 -070065
66 // Keys used for arguments bundle
67 private static final String BUNDLE_KEY_ACCOUNT_ID = "AccountSettingsFragment.AccountId";
Ben Komalo3955f672011-05-13 13:54:42 -070068 private static final String BUNDLE_KEY_ACCOUNT_EMAIL = "AccountSettingsFragment.Email";
Andrew Stadler2ae2a122010-08-18 11:29:46 -070069
Todd Kennedy34704852011-02-18 16:02:49 -080070 public static final String PREFERENCE_DESCRIPTION = "account_description";
Andrew Stadler71cc0352010-08-09 10:36:50 -070071 private static final String PREFERENCE_NAME = "account_name";
72 private static final String PREFERENCE_SIGNATURE = "account_signature";
Jorge Lugo5a3888f2011-06-01 10:09:26 -070073 private static final String PREFERENCE_QUICK_RESPONSES = "account_quick_responses";
Andrew Stadler71cc0352010-08-09 10:36:50 -070074 private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
Andy Stadler946239e2011-01-18 10:53:37 -080075 private static final String PREFERENCE_BACKGROUND_ATTACHMENTS =
76 "account_background_attachments";
Andrew Stadler71cc0352010-08-09 10:36:50 -070077 private static final String PREFERENCE_DEFAULT = "account_default";
Ben Komalo72a24f12011-07-22 15:15:47 -070078 private static final String PREFERENCE_CATEGORY_DATA_USAGE = "data_usage";
Andy Stadler9ce244b2010-11-04 21:13:45 -070079 private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "account_notifications";
Andrew Stadler71cc0352010-08-09 10:36:50 -070080 private static final String PREFERENCE_NOTIFY = "account_notify";
81 private static final String PREFERENCE_VIBRATE_WHEN = "account_settings_vibrate_when";
82 private static final String PREFERENCE_RINGTONE = "account_ringtone";
Andy Stadler9ce244b2010-11-04 21:13:45 -070083 private static final String PREFERENCE_CATEGORY_SERVER = "account_servers";
Andrew Stadler71cc0352010-08-09 10:36:50 -070084 private static final String PREFERENCE_INCOMING = "incoming";
85 private static final String PREFERENCE_OUTGOING = "outgoing";
86 private static final String PREFERENCE_SYNC_CONTACTS = "account_sync_contacts";
87 private static final String PREFERENCE_SYNC_CALENDAR = "account_sync_calendar";
Marc Blankcae86262010-10-07 15:04:20 -070088 private static final String PREFERENCE_SYNC_EMAIL = "account_sync_email";
Andrew Stadlera14a24a2010-08-19 16:28:52 -070089 private static final String PREFERENCE_DELETE_ACCOUNT = "delete_account";
Andrew Stadler71cc0352010-08-09 10:36:50 -070090
91 // These strings must match account_settings_vibrate_when_* strings in strings.xml
92 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS = "always";
93 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_SILENT = "silent";
94 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_NEVER = "never";
95
96 private EditTextPreference mAccountDescription;
97 private EditTextPreference mAccountName;
98 private EditTextPreference mAccountSignature;
99 private ListPreference mCheckFrequency;
100 private ListPreference mSyncWindow;
Andy Stadler946239e2011-01-18 10:53:37 -0800101 private CheckBoxPreference mAccountBackgroundAttachments;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700102 private CheckBoxPreference mAccountDefault;
103 private CheckBoxPreference mAccountNotify;
104 private ListPreference mAccountVibrateWhen;
105 private RingtonePreference mAccountRingtone;
106 private CheckBoxPreference mSyncContacts;
107 private CheckBoxPreference mSyncCalendar;
Marc Blankcae86262010-10-07 15:04:20 -0700108 private CheckBoxPreference mSyncEmail;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700109
110 private Context mContext;
111 private Account mAccount;
112 private boolean mAccountDirty;
Andy Stadler9f7e3982010-12-22 13:55:19 -0800113 private long mDefaultAccountId;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700114 private Callback mCallback = EmptyCallback.INSTANCE;
115 private boolean mStarted;
116 private boolean mLoaded;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700117 private boolean mSaveOnExit;
118
Ben Komalo3955f672011-05-13 13:54:42 -0700119 /** The e-mail of the account being edited. */
120 private String mAccountEmail;
121
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700122 // Async Tasks
123 private AsyncTask<?,?,?> mLoadAccountTask;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700124
125 /**
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700126 * Callback interface that owning activities must provide
Andrew Stadler71cc0352010-08-09 10:36:50 -0700127 */
128 public interface Callback {
Todd Kennedy34704852011-02-18 16:02:49 -0800129 public void onSettingsChanged(Account account, String preference, Object value);
Jorge Lugo5a3888f2011-06-01 10:09:26 -0700130 public void onEditQuickResponses(Account account);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700131 public void onIncomingSettings(Account account);
132 public void onOutgoingSettings(Account account);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700133 public void abandonEdit();
Andrew Stadlera14a24a2010-08-19 16:28:52 -0700134 public void deleteAccount(Account account);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700135 }
136
137 private static class EmptyCallback implements Callback {
138 public static final Callback INSTANCE = new EmptyCallback();
Todd Kennedy34704852011-02-18 16:02:49 -0800139 @Override public void onSettingsChanged(Account account, String preference, Object value) {}
Jorge Lugo5a3888f2011-06-01 10:09:26 -0700140 @Override public void onEditQuickResponses(Account account) {}
Todd Kennedy34704852011-02-18 16:02:49 -0800141 @Override public void onIncomingSettings(Account account) {}
142 @Override public void onOutgoingSettings(Account account) {}
143 @Override public void abandonEdit() {}
144 @Override public void deleteAccount(Account account) {}
Andrew Stadler71cc0352010-08-09 10:36:50 -0700145 }
146
147 /**
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700148 * If launching with an arguments bundle, use this method to build the arguments.
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700149 */
Ben Komalo3955f672011-05-13 13:54:42 -0700150 public static Bundle buildArguments(long accountId, String email) {
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700151 Bundle b = new Bundle();
152 b.putLong(BUNDLE_KEY_ACCOUNT_ID, accountId);
Ben Komalo3955f672011-05-13 13:54:42 -0700153 b.putString(BUNDLE_KEY_ACCOUNT_EMAIL, email);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700154 return b;
155 }
156
Ben Komalo3955f672011-05-13 13:54:42 -0700157 public static String getTitleFromArgs(Bundle args) {
158 return (args == null) ? null : args.getString(BUNDLE_KEY_ACCOUNT_EMAIL);
159 }
160
Marc Blankcae86262010-10-07 15:04:20 -0700161 @Override
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700162 public void onAttach(Activity activity) {
163 super.onAttach(activity);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700164 mContext = activity;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700165 }
166
167 /**
Andrew Stadler71cc0352010-08-09 10:36:50 -0700168 * Called to do initial creation of a fragment. This is called after
169 * {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}.
170 */
171 @Override
172 public void onCreate(Bundle savedInstanceState) {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700173 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800174 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onCreate");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700175 }
176 super.onCreate(savedInstanceState);
177
178 // Load the preferences from an XML resource
179 addPreferencesFromResource(R.xml.account_settings_preferences);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700180
181 // Start loading the account data, if provided in the arguments
182 // If not, activity must call startLoadingAccount() directly
183 Bundle b = getArguments();
184 if (b != null) {
185 long accountId = b.getLong(BUNDLE_KEY_ACCOUNT_ID, -1);
Ben Komalo3955f672011-05-13 13:54:42 -0700186 mAccountEmail = b.getString(BUNDLE_KEY_ACCOUNT_EMAIL);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700187 if (accountId >= 0 && !mLoaded) {
188 startLoadingAccount(accountId);
189 }
190 }
Andrew Stadler55110ca2010-09-07 22:20:51 -0700191
192 mAccountDirty = false;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700193 }
194
195 @Override
196 public void onActivityCreated(Bundle savedInstanceState) {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700197 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800198 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onActivityCreated");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700199 }
200 super.onActivityCreated(savedInstanceState);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700201 }
202
203 /**
204 * Called when the Fragment is visible to the user.
205 */
206 @Override
207 public void onStart() {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700208 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800209 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onStart");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700210 }
211 super.onStart();
212 mStarted = true;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700213
214 // If the loaded account is ready now, load the UI
Andrew Stadler71cc0352010-08-09 10:36:50 -0700215 if (mAccount != null && !mLoaded) {
216 loadSettings();
217 }
218 }
219
220 /**
221 * Called when the fragment is visible to the user and actively running.
Andy Stadler9f7e3982010-12-22 13:55:19 -0800222 * TODO: Don't read account data on UI thread. This should be fixed by removing the need
223 * to do this, not by spinning up yet another thread.
Andrew Stadler71cc0352010-08-09 10:36:50 -0700224 */
225 @Override
226 public void onResume() {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700227 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800228 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onResume");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700229 }
230 super.onResume();
231
232 if (mAccountDirty) {
233 // if we are coming back from editing incoming or outgoing settings,
234 // we need to refresh them here so we don't accidentally overwrite the
235 // old values we're still holding here
236 mAccount.mHostAuthRecv =
237 HostAuth.restoreHostAuthWithId(mContext, mAccount.mHostAuthKeyRecv);
238 mAccount.mHostAuthSend =
239 HostAuth.restoreHostAuthWithId(mContext, mAccount.mHostAuthKeySend);
240 // Because "delete policy" UI is on edit incoming settings, we have
241 // to refresh that as well.
242 Account refreshedAccount = Account.restoreAccountWithId(mContext, mAccount.mId);
243 if (refreshedAccount == null || mAccount.mHostAuthRecv == null
244 || mAccount.mHostAuthSend == null) {
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700245 mSaveOnExit = false;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700246 mCallback.abandonEdit();
247 return;
248 }
249 mAccount.setDeletePolicy(refreshedAccount.getDeletePolicy());
250 mAccountDirty = false;
251 }
252 }
253
254 @Override
255 public void onPause() {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700256 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800257 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onPause");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700258 }
259 super.onPause();
Andy Stadler9f7e3982010-12-22 13:55:19 -0800260 if (mSaveOnExit) {
261 saveSettings();
262 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700263 }
264
265 /**
266 * Called when the Fragment is no longer started.
267 */
268 @Override
269 public void onStop() {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700270 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800271 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onStop");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700272 }
273 super.onStop();
274 mStarted = false;
275 }
276
277 /**
278 * Called when the fragment is no longer in use.
279 */
280 @Override
281 public void onDestroy() {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700282 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800283 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onDestroy");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700284 }
285 super.onDestroy();
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700286
287 Utility.cancelTaskInterrupt(mLoadAccountTask);
288 mLoadAccountTask = null;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700289 }
290
291 @Override
292 public void onSaveInstanceState(Bundle outState) {
Makoto Onukibfac9f22011-05-13 11:20:04 -0700293 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Marc Blank31d9acb2011-02-11 15:05:17 -0800294 Log.d(Logging.LOG_TAG, "AccountSettingsFragment onSaveInstanceState");
Andrew Stadler71cc0352010-08-09 10:36:50 -0700295 }
296 super.onSaveInstanceState(outState);
297 }
298
299 /**
300 * Activity provides callbacks here
301 */
302 public void setCallback(Callback callback) {
303 mCallback = (callback == null) ? EmptyCallback.INSTANCE : callback;
304 }
305
306 /**
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700307 * Start loading a single account in preparation for editing it
Andrew Stadler71cc0352010-08-09 10:36:50 -0700308 */
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700309 public void startLoadingAccount(long accountId) {
310 Utility.cancelTaskInterrupt(mLoadAccountTask);
Makoto Onukibc2eaad2011-06-30 16:10:06 -0700311 mLoadAccountTask = new LoadAccountTask().executeOnExecutor(
312 AsyncTask.THREAD_POOL_EXECUTOR, accountId);
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700313 }
314
315 /**
316 * Async task to load account in order to view/edit it
317 */
Andy Stadler9f7e3982010-12-22 13:55:19 -0800318 private class LoadAccountTask extends AsyncTask<Long, Void, Object[]> {
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700319 @Override
Andy Stadler9f7e3982010-12-22 13:55:19 -0800320 protected Object[] doInBackground(Long... params) {
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700321 long accountId = params[0];
322 Account account = Account.restoreAccountWithId(mContext, accountId);
323 if (account != null) {
324 account.mHostAuthRecv =
325 HostAuth.restoreHostAuthWithId(mContext, account.mHostAuthKeyRecv);
326 account.mHostAuthSend =
327 HostAuth.restoreHostAuthWithId(mContext, account.mHostAuthKeySend);
328 if (account.mHostAuthRecv == null || account.mHostAuthSend == null) {
329 account = null;
330 }
331 }
Andy Stadler9f7e3982010-12-22 13:55:19 -0800332 long defaultAccountId = Account.getDefaultAccountId(mContext);
333 return new Object[] { account, Long.valueOf(defaultAccountId) };
Andrew Stadler71cc0352010-08-09 10:36:50 -0700334 }
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700335
336 @Override
Andy Stadler9f7e3982010-12-22 13:55:19 -0800337 protected void onPostExecute(Object[] results) {
338 if (results != null && !isCancelled()) {
339 Account account = (Account) results[0];
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700340 if (account == null) {
341 mSaveOnExit = false;
342 mCallback.abandonEdit();
343 } else {
344 mAccount = account;
Andy Stadler9f7e3982010-12-22 13:55:19 -0800345 mDefaultAccountId = (Long) results[1];
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700346 if (mStarted && !mLoaded) {
347 loadSettings();
348 }
349 }
350 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700351 }
352 }
353
354 /**
355 * Load account data into preference UI
356 */
357 private void loadSettings() {
358 // We can only do this once, so prevent repeat
359 mLoaded = true;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700360 // Once loaded the data is ready to be saved, as well
Andy Stadler9f7e3982010-12-22 13:55:19 -0800361 mSaveOnExit = false;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700362
Andrew Stadler71cc0352010-08-09 10:36:50 -0700363 mAccountDescription = (EditTextPreference) findPreference(PREFERENCE_DESCRIPTION);
364 mAccountDescription.setSummary(mAccount.getDisplayName());
365 mAccountDescription.setText(mAccount.getDisplayName());
366 mAccountDescription.setOnPreferenceChangeListener(
367 new Preference.OnPreferenceChangeListener() {
368 public boolean onPreferenceChange(Preference preference, Object newValue) {
Andy Stadler373ccb12011-01-20 11:37:39 -0800369 String summary = newValue.toString().trim();
370 if (TextUtils.isEmpty(summary)) {
371 summary = mAccount.mEmailAddress;
372 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700373 mAccountDescription.setSummary(summary);
374 mAccountDescription.setText(summary);
Todd Kennedy34704852011-02-18 16:02:49 -0800375 onPreferenceChanged(PREFERENCE_DESCRIPTION, summary);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700376 return false;
377 }
378 }
379 );
380
381 mAccountName = (EditTextPreference) findPreference(PREFERENCE_NAME);
Andy Stadler2d6a98a2011-03-01 22:19:53 -0800382 String senderName = mAccount.getSenderName();
383 // In rare cases, sendername will be null; Change this to empty string to avoid NPE's
384 if (senderName == null) senderName = "";
385 mAccountName.setSummary(senderName);
386 mAccountName.setText(senderName);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700387 mAccountName.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
388 public boolean onPreferenceChange(Preference preference, Object newValue) {
Andy Stadler373ccb12011-01-20 11:37:39 -0800389 final String summary = newValue.toString().trim();
390 if (!TextUtils.isEmpty(summary)) {
391 mAccountName.setSummary(summary);
392 mAccountName.setText(summary);
Todd Kennedy34704852011-02-18 16:02:49 -0800393 onPreferenceChanged(PREFERENCE_NAME, summary);
Andy Stadler373ccb12011-01-20 11:37:39 -0800394 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700395 return false;
396 }
397 });
398
399 mAccountSignature = (EditTextPreference) findPreference(PREFERENCE_SIGNATURE);
Andy Stadler373ccb12011-01-20 11:37:39 -0800400 String signature = mAccount.getSignature();
Andrew Stadler71cc0352010-08-09 10:36:50 -0700401 mAccountSignature.setText(mAccount.getSignature());
402 mAccountSignature.setOnPreferenceChangeListener(
Andy Stadler4fd1ebd2011-01-24 12:01:43 -0800403 new Preference.OnPreferenceChangeListener() {
404 public boolean onPreferenceChange(Preference preference, Object newValue) {
405 // Clean up signature if it's only whitespace (which is easy to do on a
406 // soft keyboard) but leave whitespace in place otherwise, to give the user
407 // maximum flexibility, e.g. the ability to indent
408 String signature = newValue.toString();
409 if (signature.trim().isEmpty()) {
410 signature = "";
Andrew Stadler71cc0352010-08-09 10:36:50 -0700411 }
Andy Stadler4fd1ebd2011-01-24 12:01:43 -0800412 mAccountSignature.setText(signature);
Todd Kennedy34704852011-02-18 16:02:49 -0800413 onPreferenceChanged(PREFERENCE_SIGNATURE, signature);
Andy Stadler4fd1ebd2011-01-24 12:01:43 -0800414 return false;
415 }
416 });
Andrew Stadler71cc0352010-08-09 10:36:50 -0700417
418 mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
419
Marc Blank85e4c102011-06-08 13:50:00 -0700420 // TODO Move protocol into Account to avoid retrieving the HostAuth (implicitly)
421 String protocol = Account.getProtocol(mContext, mAccount.mId);
422 if (HostAuth.SCHEME_EAS.equals(protocol)) {
Andrew Stadler71cc0352010-08-09 10:36:50 -0700423 mCheckFrequency.setEntries(R.array.account_settings_check_frequency_entries_push);
424 mCheckFrequency.setEntryValues(R.array.account_settings_check_frequency_values_push);
425 }
426
427 mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval()));
428 mCheckFrequency.setSummary(mCheckFrequency.getEntry());
429 mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
430 public boolean onPreferenceChange(Preference preference, Object newValue) {
431 final String summary = newValue.toString();
432 int index = mCheckFrequency.findIndexOfValue(summary);
433 mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]);
434 mCheckFrequency.setValue(summary);
Todd Kennedy34704852011-02-18 16:02:49 -0800435 onPreferenceChanged(PREFERENCE_FREQUENCY, newValue);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700436 return false;
437 }
438 });
439
Jorge Lugo5a3888f2011-06-01 10:09:26 -0700440 findPreference(PREFERENCE_QUICK_RESPONSES).setOnPreferenceClickListener(
441 new Preference.OnPreferenceClickListener() {
442 @Override
443 public boolean onPreferenceClick(Preference preference) {
444 mAccountDirty = true;
445 mCallback.onEditQuickResponses(mAccount);
446 return true;
447 }
448 });
449
Andrew Stadler71cc0352010-08-09 10:36:50 -0700450 // Add check window preference
Ben Komalo72a24f12011-07-22 15:15:47 -0700451 PreferenceCategory dataUsageCategory =
452 (PreferenceCategory) findPreference(PREFERENCE_CATEGORY_DATA_USAGE);
453
Andrew Stadler71cc0352010-08-09 10:36:50 -0700454 mSyncWindow = null;
Ben Komalo82e0e1c2011-06-14 19:10:28 -0700455 if (HostAuth.SCHEME_EAS.equals(protocol)) {
Andrew Stadler71cc0352010-08-09 10:36:50 -0700456 mSyncWindow = new ListPreference(mContext);
457 mSyncWindow.setTitle(R.string.account_setup_options_mail_window_label);
458 mSyncWindow.setEntries(R.array.account_settings_mail_window_entries);
459 mSyncWindow.setEntryValues(R.array.account_settings_mail_window_values);
460 mSyncWindow.setValue(String.valueOf(mAccount.getSyncLookback()));
461 mSyncWindow.setSummary(mSyncWindow.getEntry());
Ben Komalo72a24f12011-07-22 15:15:47 -0700462
463 // Must correspond to the hole in the XML file that's reserved.
464 mSyncWindow.setOrder(2);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700465 mSyncWindow.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
466 public boolean onPreferenceChange(Preference preference, Object newValue) {
467 final String summary = newValue.toString();
468 int index = mSyncWindow.findIndexOfValue(summary);
469 mSyncWindow.setSummary(mSyncWindow.getEntries()[index]);
470 mSyncWindow.setValue(summary);
Todd Kennedy34704852011-02-18 16:02:49 -0800471 onPreferenceChanged(preference.getKey(), newValue);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700472 return false;
473 }
474 });
Ben Komalo72a24f12011-07-22 15:15:47 -0700475 dataUsageCategory.addPreference(mSyncWindow);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700476 }
477
Andy Stadler946239e2011-01-18 10:53:37 -0800478 // Show "background attachments" for IMAP & EAS - hide it for POP3.
479 mAccountBackgroundAttachments = (CheckBoxPreference)
480 findPreference(PREFERENCE_BACKGROUND_ATTACHMENTS);
Marc Blank85e4c102011-06-08 13:50:00 -0700481 if (HostAuth.SCHEME_POP3.equals(mAccount.mHostAuthRecv.mProtocol)) {
Ben Komalo72a24f12011-07-22 15:15:47 -0700482 dataUsageCategory.removePreference(mAccountBackgroundAttachments);
Andy Stadler946239e2011-01-18 10:53:37 -0800483 } else {
484 mAccountBackgroundAttachments.setChecked(
485 0 != (mAccount.getFlags() & Account.FLAGS_BACKGROUND_ATTACHMENTS));
486 mAccountBackgroundAttachments.setOnPreferenceChangeListener(mPreferenceChangeListener);
487 }
488
Andrew Stadler71cc0352010-08-09 10:36:50 -0700489 mAccountDefault = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT);
Andy Stadler9f7e3982010-12-22 13:55:19 -0800490 mAccountDefault.setChecked(mAccount.mId == mDefaultAccountId);
491 mAccountDefault.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700492
493 mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
494 mAccountNotify.setChecked(0 != (mAccount.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL));
Andy Stadler9f7e3982010-12-22 13:55:19 -0800495 mAccountNotify.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700496
497 mAccountRingtone = (RingtonePreference) findPreference(PREFERENCE_RINGTONE);
Andy Stadler9f7e3982010-12-22 13:55:19 -0800498 mAccountRingtone.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700499
500 // The following two lines act as a workaround for the RingtonePreference
501 // which does not let us set/get the value programmatically
502 SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
Brad Fitzpatrickbd29c302010-11-01 08:51:26 -0700503 prefs.edit().putString(PREFERENCE_RINGTONE, mAccount.getRingtone()).apply();
Andrew Stadler71cc0352010-08-09 10:36:50 -0700504
Andy Stadler9ce244b2010-11-04 21:13:45 -0700505 // Set the vibrator value, or hide it on devices w/o a vibrator
Andrew Stadler71cc0352010-08-09 10:36:50 -0700506 mAccountVibrateWhen = (ListPreference) findPreference(PREFERENCE_VIBRATE_WHEN);
Andy Stadler9ce244b2010-11-04 21:13:45 -0700507 Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
508 if (vibrator.hasVibrator()) {
509 boolean flagsVibrate = 0 != (mAccount.getFlags() & Account.FLAGS_VIBRATE_ALWAYS);
510 boolean flagsVibrateSilent =
511 0 != (mAccount.getFlags() & Account.FLAGS_VIBRATE_WHEN_SILENT);
512 mAccountVibrateWhen.setValue(
513 flagsVibrate ? PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS :
514 flagsVibrateSilent ? PREFERENCE_VALUE_VIBRATE_WHEN_SILENT :
515 PREFERENCE_VALUE_VIBRATE_WHEN_NEVER);
Andy Stadler9f7e3982010-12-22 13:55:19 -0800516 mAccountVibrateWhen.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andy Stadler9ce244b2010-11-04 21:13:45 -0700517 } else {
518 PreferenceCategory notificationsCategory = (PreferenceCategory)
519 findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS);
520 notificationsCategory.removePreference(mAccountVibrateWhen);
521 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700522
523 findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener(
524 new Preference.OnPreferenceClickListener() {
525 public boolean onPreferenceClick(Preference preference) {
526 mAccountDirty = true;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700527 mCallback.onIncomingSettings(mAccount);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700528 return true;
529 }
530 });
531
532 // Hide the outgoing account setup link if it's not activated
533 Preference prefOutgoing = findPreference(PREFERENCE_OUTGOING);
534 boolean showOutgoing = true;
535 try {
Todd Kennedydaf869c2011-04-20 08:04:46 -0700536 Sender sender = Sender.getInstance(mContext, mAccount);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700537 if (sender != null) {
538 Class<? extends android.app.Activity> setting = sender.getSettingActivityClass();
539 showOutgoing = (setting != null);
540 }
541 } catch (MessagingException me) {
542 // just leave showOutgoing as true - bias towards showing it, so user can fix it
543 }
544 if (showOutgoing) {
545 prefOutgoing.setOnPreferenceClickListener(
546 new Preference.OnPreferenceClickListener() {
547 public boolean onPreferenceClick(Preference preference) {
548 mAccountDirty = true;
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700549 mCallback.onOutgoingSettings(mAccount);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700550 return true;
551 }
552 });
553 } else {
554 PreferenceCategory serverCategory = (PreferenceCategory) findPreference(
Andy Stadler9ce244b2010-11-04 21:13:45 -0700555 PREFERENCE_CATEGORY_SERVER);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700556 serverCategory.removePreference(prefOutgoing);
557 }
558
559 mSyncContacts = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CONTACTS);
560 mSyncCalendar = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CALENDAR);
Marc Blankcae86262010-10-07 15:04:20 -0700561 mSyncEmail = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_EMAIL);
Ben Komalo72a24f12011-07-22 15:15:47 -0700562 if (mAccount.mHostAuthRecv.mProtocol.equals(HostAuth.SCHEME_EAS)) {
Andrew Stadler71cc0352010-08-09 10:36:50 -0700563 android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress,
Marc Blank3a5c1fb2011-02-12 18:56:09 -0800564 AccountManagerTypes.TYPE_EXCHANGE);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700565 mSyncContacts.setChecked(ContentResolver
566 .getSyncAutomatically(acct, ContactsContract.AUTHORITY));
Andy Stadler9f7e3982010-12-22 13:55:19 -0800567 mSyncContacts.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700568 mSyncCalendar.setChecked(ContentResolver
Marc Blank31d9acb2011-02-11 15:05:17 -0800569 .getSyncAutomatically(acct, CalendarProviderStub.AUTHORITY));
Andy Stadler9f7e3982010-12-22 13:55:19 -0800570 mSyncCalendar.setOnPreferenceChangeListener(mPreferenceChangeListener);
Marc Blankcae86262010-10-07 15:04:20 -0700571 mSyncEmail.setChecked(ContentResolver
572 .getSyncAutomatically(acct, EmailContent.AUTHORITY));
Andy Stadler9f7e3982010-12-22 13:55:19 -0800573 mSyncEmail.setOnPreferenceChangeListener(mPreferenceChangeListener);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700574 } else {
Ben Komalo72a24f12011-07-22 15:15:47 -0700575 dataUsageCategory.removePreference(mSyncContacts);
576 dataUsageCategory.removePreference(mSyncCalendar);
577 dataUsageCategory.removePreference(mSyncEmail);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700578 }
Andrew Stadlera14a24a2010-08-19 16:28:52 -0700579
580 // Temporary home for delete account
581 Preference prefDeleteAccount = findPreference(PREFERENCE_DELETE_ACCOUNT);
582 prefDeleteAccount.setOnPreferenceClickListener(
583 new Preference.OnPreferenceClickListener() {
584 public boolean onPreferenceClick(Preference preference) {
585 DeleteAccountFragment dialogFragment = DeleteAccountFragment.newInstance(
586 mAccount, AccountSettingsFragment.this);
Dianne Hackborn31e25762011-01-17 12:30:51 -0800587 FragmentTransaction ft = getFragmentManager().beginTransaction();
Dianne Hackborna2cc46c2010-09-12 19:38:10 -0700588 ft.addToBackStack(null);
589 dialogFragment.show(ft, DeleteAccountFragment.TAG);
Andrew Stadlera14a24a2010-08-19 16:28:52 -0700590 return true;
591 }
592 });
Andrew Stadler71cc0352010-08-09 10:36:50 -0700593 }
594
Andy Stadler9f7e3982010-12-22 13:55:19 -0800595 /**
596 * Generic onPreferenceChanged listener for the preferences (above) that just need
597 * to be written, without extra tweaks
Andrew Stadler2ae2a122010-08-18 11:29:46 -0700598 */
Ben Komalo28662842011-05-12 17:27:56 -0700599 private final Preference.OnPreferenceChangeListener mPreferenceChangeListener =
Andy Stadler9f7e3982010-12-22 13:55:19 -0800600 new Preference.OnPreferenceChangeListener() {
601 public boolean onPreferenceChange(Preference preference, Object newValue) {
Todd Kennedy34704852011-02-18 16:02:49 -0800602 onPreferenceChanged(preference.getKey(), newValue);
Andy Stadler9f7e3982010-12-22 13:55:19 -0800603 return true;
604 }
605 };
606
607 /**
608 * Called any time a preference is changed.
609 */
Todd Kennedy34704852011-02-18 16:02:49 -0800610 private void onPreferenceChanged(String preference, Object value) {
611 mCallback.onSettingsChanged(mAccount, preference, value);
Andy Stadler9f7e3982010-12-22 13:55:19 -0800612 mSaveOnExit = true;
613 }
614
615 /*
616 * Note: This writes the settings on the UI thread. This has to be done so the settings are
617 * committed before we might be killed.
618 */
619 private void saveSettings() {
Andy Stadler946239e2011-01-18 10:53:37 -0800620 // Turn off all controlled flags - will turn them back on while checking UI elements
Andrew Stadler71cc0352010-08-09 10:36:50 -0700621 int newFlags = mAccount.getFlags() &
622 ~(Account.FLAGS_NOTIFY_NEW_MAIL |
Andy Stadler946239e2011-01-18 10:53:37 -0800623 Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_VIBRATE_WHEN_SILENT |
624 Account.FLAGS_BACKGROUND_ATTACHMENTS);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700625
Ben Komalo28662842011-05-12 17:27:56 -0700626 newFlags |= mAccountBackgroundAttachments.isChecked() ?
Andy Stadler946239e2011-01-18 10:53:37 -0800627 Account.FLAGS_BACKGROUND_ATTACHMENTS : 0;
Andrew Stadler71cc0352010-08-09 10:36:50 -0700628 mAccount.setDefaultAccount(mAccountDefault.isChecked());
Andy Stadler373ccb12011-01-20 11:37:39 -0800629 // If the display name has been cleared, we'll reset it to the default value (email addr)
630 mAccount.setDisplayName(mAccountDescription.getText().trim());
631 // The sender name must never be empty (this is enforced by the preference editor)
632 mAccount.setSenderName(mAccountName.getText().trim());
Andrew Stadler71cc0352010-08-09 10:36:50 -0700633 mAccount.setSignature(mAccountSignature.getText());
634 newFlags |= mAccountNotify.isChecked() ? Account.FLAGS_NOTIFY_NEW_MAIL : 0;
635 mAccount.setSyncInterval(Integer.parseInt(mCheckFrequency.getValue()));
636 if (mSyncWindow != null) {
637 mAccount.setSyncLookback(Integer.parseInt(mSyncWindow.getValue()));
638 }
639 if (mAccountVibrateWhen.getValue().equals(PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS)) {
640 newFlags |= Account.FLAGS_VIBRATE_ALWAYS;
641 } else if (mAccountVibrateWhen.getValue().equals(PREFERENCE_VALUE_VIBRATE_WHEN_SILENT)) {
642 newFlags |= Account.FLAGS_VIBRATE_WHEN_SILENT;
643 }
644 SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
645 mAccount.setRingtone(prefs.getString(PREFERENCE_RINGTONE, null));
646 mAccount.setFlags(newFlags);
647
648 if (mAccount.mHostAuthRecv.mProtocol.equals("eas")) {
649 android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress,
Marc Blank3a5c1fb2011-02-12 18:56:09 -0800650 AccountManagerTypes.TYPE_EXCHANGE);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700651 ContentResolver.setSyncAutomatically(acct, ContactsContract.AUTHORITY,
652 mSyncContacts.isChecked());
Marc Blank31d9acb2011-02-11 15:05:17 -0800653 ContentResolver.setSyncAutomatically(acct, CalendarProviderStub.AUTHORITY,
Andrew Stadler71cc0352010-08-09 10:36:50 -0700654 mSyncCalendar.isChecked());
Marc Blankcae86262010-10-07 15:04:20 -0700655 ContentResolver.setSyncAutomatically(acct, EmailContent.AUTHORITY,
656 mSyncEmail.isChecked());
Andrew Stadler71cc0352010-08-09 10:36:50 -0700657 }
Andy Stadler9f7e3982010-12-22 13:55:19 -0800658
659 // Commit the changes
660 // Note, this is done in the UI thread because at this point, we must commit
661 // all changes - any time after onPause completes, we could be killed. This is analogous
662 // to the way that SharedPreferences tries to work off-thread in apply(), but will pause
663 // until completion in onPause().
664 ContentValues cv = AccountSettingsUtils.getAccountContentValues(mAccount);
665 mAccount.update(mContext, cv);
666
667 // Run the remaining changes off-thread
Andy Stadler2959a7e2010-12-23 13:19:55 -0800668 Email.setServicesEnabledAsync(mContext);
Andrew Stadler71cc0352010-08-09 10:36:50 -0700669 }
Andrew Stadlera14a24a2010-08-19 16:28:52 -0700670
671 /**
672 * Dialog fragment to show "remove account?" dialog
673 */
674 public static class DeleteAccountFragment extends DialogFragment {
675 private final static String TAG = "DeleteAccountFragment";
676
677 // Argument bundle keys
678 private final static String BUNDLE_KEY_ACCOUNT_NAME = "DeleteAccountFragment.Name";
679
680 /**
681 * Create the dialog with parameters
682 */
683 public static DeleteAccountFragment newInstance(Account account, Fragment parentFragment) {
684 DeleteAccountFragment f = new DeleteAccountFragment();
685 Bundle b = new Bundle();
686 b.putString(BUNDLE_KEY_ACCOUNT_NAME, account.getDisplayName());
687 f.setArguments(b);
688 f.setTargetFragment(parentFragment, 0);
689 return f;
690 }
691
692 @Override
693 public Dialog onCreateDialog(Bundle savedInstanceState) {
694 Context context = getActivity();
695 final String name = getArguments().getString(BUNDLE_KEY_ACCOUNT_NAME);
696
697 return new AlertDialog.Builder(context)
Makoto Onuki49518bb2011-01-18 10:14:14 -0800698 .setIconAttribute(android.R.attr.alertDialogIcon)
Andrew Stadlera14a24a2010-08-19 16:28:52 -0700699 .setTitle(R.string.account_delete_dlg_title)
700 .setMessage(context.getString(R.string.account_delete_dlg_instructions_fmt, name))
701 .setPositiveButton(
702 R.string.okay_action,
703 new DialogInterface.OnClickListener() {
704 public void onClick(DialogInterface dialog, int whichButton) {
705 Fragment f = getTargetFragment();
706 if (f instanceof AccountSettingsFragment) {
707 ((AccountSettingsFragment)f).finishDeleteAccount();
708 }
709 dismiss();
710 }
711 })
712 .setNegativeButton(
713 R.string.cancel_action,
714 new DialogInterface.OnClickListener() {
715 public void onClick(DialogInterface dialog, int whichButton) {
716 dismiss();
717 }
718 })
719 .create();
720 }
721 }
722
723 /**
724 * Callback from delete account dialog - passes the delete command up to the activity
725 */
726 private void finishDeleteAccount() {
727 mSaveOnExit = false;
728 mCallback.deleteAccount(mAccount);
729 }
Ben Komalo3955f672011-05-13 13:54:42 -0700730
731 public String getAccountEmail() {
732 // Get the e-mail address of the account being editted, if this is for an existing account.
733 return mAccountEmail;
734 }
Andrew Stadler71cc0352010-08-09 10:36:50 -0700735}