AccountSettingsFragment.java revision f72f812f5bb5d14940b2b161eec417a9aa6950f8
1/* 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 19import com.android.email.Email; 20import com.android.email.R; 21import com.android.email.Utility; 22import com.android.email.mail.MessagingException; 23import com.android.email.mail.Sender; 24import com.android.email.mail.Store; 25import com.android.email.provider.EmailContent; 26import com.android.email.provider.EmailContent.Account; 27import com.android.email.provider.EmailContent.HostAuth; 28 29import android.app.Activity; 30import android.app.AlertDialog; 31import android.app.Dialog; 32import android.app.DialogFragment; 33import android.app.Fragment; 34import android.app.FragmentTransaction; 35import android.content.ContentResolver; 36import android.content.ContentValues; 37import android.content.Context; 38import android.content.DialogInterface; 39import android.content.SharedPreferences; 40import android.os.AsyncTask; 41import android.os.Bundle; 42import android.os.Vibrator; 43import android.preference.CheckBoxPreference; 44import android.preference.EditTextPreference; 45import android.preference.ListPreference; 46import android.preference.Preference; 47import android.preference.PreferenceCategory; 48import android.preference.PreferenceFragment; 49import android.preference.RingtonePreference; 50import android.provider.Calendar; 51import android.provider.ContactsContract; 52import android.util.Log; 53 54/** 55 * Fragment containing the main logic for account settings. This also calls out to other 56 * fragments for server settings. 57 * 58 * TODO: Remove or make async the mAccountDirty reload logic. Probably no longer needed. 59 * TODO: Can we defer calling addPreferencesFromResource() until after we load the account? This 60 * could reduce flicker. 61 */ 62public class AccountSettingsFragment extends PreferenceFragment { 63 64 // Keys used for arguments bundle 65 private static final String BUNDLE_KEY_ACCOUNT_ID = "AccountSettingsFragment.AccountId"; 66 67 private static final String PREFERENCE_CATEGORY_TOP = "account_settings"; 68 private static final String PREFERENCE_DESCRIPTION = "account_description"; 69 private static final String PREFERENCE_NAME = "account_name"; 70 private static final String PREFERENCE_SIGNATURE = "account_signature"; 71 private static final String PREFERENCE_FREQUENCY = "account_check_frequency"; 72 private static final String PREFERENCE_BACKGROUND_ATTACHMENTS = 73 "account_background_attachments"; 74 private static final String PREFERENCE_DEFAULT = "account_default"; 75 private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "account_notifications"; 76 private static final String PREFERENCE_NOTIFY = "account_notify"; 77 private static final String PREFERENCE_VIBRATE_WHEN = "account_settings_vibrate_when"; 78 private static final String PREFERENCE_RINGTONE = "account_ringtone"; 79 private static final String PREFERENCE_CATEGORY_SERVER = "account_servers"; 80 private static final String PREFERENCE_INCOMING = "incoming"; 81 private static final String PREFERENCE_OUTGOING = "outgoing"; 82 private static final String PREFERENCE_SYNC_CONTACTS = "account_sync_contacts"; 83 private static final String PREFERENCE_SYNC_CALENDAR = "account_sync_calendar"; 84 private static final String PREFERENCE_SYNC_EMAIL = "account_sync_email"; 85 private static final String PREFERENCE_DELETE_ACCOUNT = "delete_account"; 86 87 // These strings must match account_settings_vibrate_when_* strings in strings.xml 88 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS = "always"; 89 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_SILENT = "silent"; 90 private static final String PREFERENCE_VALUE_VIBRATE_WHEN_NEVER = "never"; 91 92 private EditTextPreference mAccountDescription; 93 private EditTextPreference mAccountName; 94 private EditTextPreference mAccountSignature; 95 private ListPreference mCheckFrequency; 96 private ListPreference mSyncWindow; 97 private CheckBoxPreference mAccountBackgroundAttachments; 98 private CheckBoxPreference mAccountDefault; 99 private CheckBoxPreference mAccountNotify; 100 private ListPreference mAccountVibrateWhen; 101 private RingtonePreference mAccountRingtone; 102 private CheckBoxPreference mSyncContacts; 103 private CheckBoxPreference mSyncCalendar; 104 private CheckBoxPreference mSyncEmail; 105 106 private Context mContext; 107 private Account mAccount; 108 private boolean mAccountDirty; 109 private long mDefaultAccountId; 110 private Callback mCallback = EmptyCallback.INSTANCE; 111 private boolean mStarted; 112 private boolean mLoaded; 113 private boolean mSaveOnExit; 114 115 // Async Tasks 116 private AsyncTask<?,?,?> mLoadAccountTask; 117 118 /** 119 * Callback interface that owning activities must provide 120 */ 121 public interface Callback { 122 public void onIncomingSettings(Account account); 123 public void onOutgoingSettings(Account account); 124 public void abandonEdit(); 125 public void deleteAccount(Account account); 126 } 127 128 private static class EmptyCallback implements Callback { 129 public static final Callback INSTANCE = new EmptyCallback(); 130 @Override public void onIncomingSettings(Account account) { } 131 @Override public void onOutgoingSettings(Account account) { } 132 @Override public void abandonEdit() { } 133 @Override public void deleteAccount(Account account) { } 134 } 135 136 /** 137 * If launching with an arguments bundle, use this method to build the arguments. 138 * @param accountId The account being modified 139 */ 140 public static Bundle buildArguments(long accountId) { 141 Bundle b = new Bundle(); 142 b.putLong(BUNDLE_KEY_ACCOUNT_ID, accountId); 143 return b; 144 } 145 146 /** 147 * Called when a fragment is first attached to its activity. 148 * {@link #onCreate(Bundle)} will be called after this. 149 */ 150 @Override 151 public void onAttach(Activity activity) { 152 super.onAttach(activity); 153 154 mContext = activity; 155 156 // Notify the activity that we're here. 157 if (activity instanceof AccountSettingsXL) { 158 ((AccountSettingsXL)activity).onAttach(this); 159 } 160 } 161 162 /** 163 * Called to do initial creation of a fragment. This is called after 164 * {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}. 165 */ 166 @Override 167 public void onCreate(Bundle savedInstanceState) { 168 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 169 Log.d(Email.LOG_TAG, "AccountSettingsFragment onCreate"); 170 } 171 super.onCreate(savedInstanceState); 172 173 // Load the preferences from an XML resource 174 addPreferencesFromResource(R.xml.account_settings_preferences); 175 176 // Start loading the account data, if provided in the arguments 177 // If not, activity must call startLoadingAccount() directly 178 Bundle b = getArguments(); 179 if (b != null) { 180 long accountId = b.getLong(BUNDLE_KEY_ACCOUNT_ID, -1); 181 if (accountId >= 0 && !mLoaded) { 182 startLoadingAccount(accountId); 183 } 184 } 185 186 mAccountDirty = false; 187 } 188 189 @Override 190 public void onActivityCreated(Bundle savedInstanceState) { 191 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 192 Log.d(Email.LOG_TAG, "AccountSettingsFragment onActivityCreated"); 193 } 194 super.onActivityCreated(savedInstanceState); 195 } 196 197 /** 198 * Called when the Fragment is visible to the user. 199 */ 200 @Override 201 public void onStart() { 202 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 203 Log.d(Email.LOG_TAG, "AccountSettingsFragment onStart"); 204 } 205 super.onStart(); 206 mStarted = true; 207 208 // If the loaded account is ready now, load the UI 209 if (mAccount != null && !mLoaded) { 210 loadSettings(); 211 } 212 } 213 214 /** 215 * Called when the fragment is visible to the user and actively running. 216 * TODO: Don't read account data on UI thread. This should be fixed by removing the need 217 * to do this, not by spinning up yet another thread. 218 */ 219 @Override 220 public void onResume() { 221 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 222 Log.d(Email.LOG_TAG, "AccountSettingsFragment onResume"); 223 } 224 super.onResume(); 225 226 if (mAccountDirty) { 227 // if we are coming back from editing incoming or outgoing settings, 228 // we need to refresh them here so we don't accidentally overwrite the 229 // old values we're still holding here 230 mAccount.mHostAuthRecv = 231 HostAuth.restoreHostAuthWithId(mContext, mAccount.mHostAuthKeyRecv); 232 mAccount.mHostAuthSend = 233 HostAuth.restoreHostAuthWithId(mContext, mAccount.mHostAuthKeySend); 234 // Because "delete policy" UI is on edit incoming settings, we have 235 // to refresh that as well. 236 Account refreshedAccount = Account.restoreAccountWithId(mContext, mAccount.mId); 237 if (refreshedAccount == null || mAccount.mHostAuthRecv == null 238 || mAccount.mHostAuthSend == null) { 239 mSaveOnExit = false; 240 mCallback.abandonEdit(); 241 return; 242 } 243 mAccount.setDeletePolicy(refreshedAccount.getDeletePolicy()); 244 mAccountDirty = false; 245 } 246 } 247 248 @Override 249 public void onPause() { 250 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 251 Log.d(Email.LOG_TAG, "AccountSettingsFragment onPause"); 252 } 253 super.onPause(); 254 if (mSaveOnExit) { 255 saveSettings(); 256 } 257 } 258 259 /** 260 * Called when the Fragment is no longer started. 261 */ 262 @Override 263 public void onStop() { 264 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 265 Log.d(Email.LOG_TAG, "AccountSettingsFragment onStop"); 266 } 267 super.onStop(); 268 mStarted = false; 269 } 270 271 /** 272 * Called when the fragment is no longer in use. 273 */ 274 @Override 275 public void onDestroy() { 276 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 277 Log.d(Email.LOG_TAG, "AccountSettingsFragment onDestroy"); 278 } 279 super.onDestroy(); 280 281 Utility.cancelTaskInterrupt(mLoadAccountTask); 282 mLoadAccountTask = null; 283 } 284 285 @Override 286 public void onSaveInstanceState(Bundle outState) { 287 if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 288 Log.d(Email.LOG_TAG, "AccountSettingsFragment onSaveInstanceState"); 289 } 290 super.onSaveInstanceState(outState); 291 } 292 293 /** 294 * Activity provides callbacks here 295 */ 296 public void setCallback(Callback callback) { 297 mCallback = (callback == null) ? EmptyCallback.INSTANCE : callback; 298 } 299 300 /** 301 * Start loading a single account in preparation for editing it 302 */ 303 public void startLoadingAccount(long accountId) { 304 Utility.cancelTaskInterrupt(mLoadAccountTask); 305 mLoadAccountTask = new LoadAccountTask().execute(accountId); 306 } 307 308 /** 309 * Async task to load account in order to view/edit it 310 */ 311 private class LoadAccountTask extends AsyncTask<Long, Void, Object[]> { 312 @Override 313 protected Object[] doInBackground(Long... params) { 314 long accountId = params[0]; 315 Account account = Account.restoreAccountWithId(mContext, accountId); 316 if (account != null) { 317 account.mHostAuthRecv = 318 HostAuth.restoreHostAuthWithId(mContext, account.mHostAuthKeyRecv); 319 account.mHostAuthSend = 320 HostAuth.restoreHostAuthWithId(mContext, account.mHostAuthKeySend); 321 if (account.mHostAuthRecv == null || account.mHostAuthSend == null) { 322 account = null; 323 } 324 } 325 long defaultAccountId = Account.getDefaultAccountId(mContext); 326 return new Object[] { account, Long.valueOf(defaultAccountId) }; 327 } 328 329 @Override 330 protected void onPostExecute(Object[] results) { 331 if (results != null && !isCancelled()) { 332 Account account = (Account) results[0]; 333 if (account == null) { 334 mSaveOnExit = false; 335 mCallback.abandonEdit(); 336 } else { 337 mAccount = account; 338 mDefaultAccountId = (Long) results[1]; 339 if (mStarted && !mLoaded) { 340 loadSettings(); 341 } 342 } 343 } 344 } 345 } 346 347 /** 348 * Load account data into preference UI 349 */ 350 private void loadSettings() { 351 // We can only do this once, so prevent repeat 352 mLoaded = true; 353 // Once loaded the data is ready to be saved, as well 354 mSaveOnExit = false; 355 356 PreferenceCategory topCategory = 357 (PreferenceCategory) findPreference(PREFERENCE_CATEGORY_TOP); 358 topCategory.setTitle(mContext.getString(R.string.account_settings_title_fmt)); 359 360 mAccountDescription = (EditTextPreference) findPreference(PREFERENCE_DESCRIPTION); 361 mAccountDescription.setSummary(mAccount.getDisplayName()); 362 mAccountDescription.setText(mAccount.getDisplayName()); 363 mAccountDescription.setOnPreferenceChangeListener( 364 new Preference.OnPreferenceChangeListener() { 365 public boolean onPreferenceChange(Preference preference, Object newValue) { 366 final String summary = newValue.toString(); 367 mAccountDescription.setSummary(summary); 368 mAccountDescription.setText(summary); 369 onPreferenceChanged(); 370 return false; 371 } 372 } 373 ); 374 375 mAccountName = (EditTextPreference) findPreference(PREFERENCE_NAME); 376 mAccountName.setSummary(mAccount.getSenderName()); 377 mAccountName.setText(mAccount.getSenderName()); 378 mAccountName.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 379 public boolean onPreferenceChange(Preference preference, Object newValue) { 380 final String summary = newValue.toString(); 381 mAccountName.setSummary(summary); 382 mAccountName.setText(summary); 383 onPreferenceChanged(); 384 return false; 385 } 386 }); 387 388 mAccountSignature = (EditTextPreference) findPreference(PREFERENCE_SIGNATURE); 389 mAccountSignature.setSummary(mAccount.getSignature()); 390 mAccountSignature.setText(mAccount.getSignature()); 391 mAccountSignature.setOnPreferenceChangeListener( 392 new Preference.OnPreferenceChangeListener() { 393 public boolean onPreferenceChange(Preference preference, Object newValue) { 394 String summary = newValue.toString(); 395 if (summary == null || summary.length() == 0) { 396 mAccountSignature.setSummary(R.string.account_settings_signature_hint); 397 } else { 398 mAccountSignature.setSummary(summary); 399 } 400 mAccountSignature.setText(summary); 401 onPreferenceChanged(); 402 return false; 403 } 404 }); 405 406 mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY); 407 408 // Before setting value, we may need to adjust the lists 409 Store.StoreInfo info = Store.StoreInfo.getStoreInfo(mAccount.getStoreUri(mContext), 410 mContext); 411 if (info.mPushSupported) { 412 mCheckFrequency.setEntries(R.array.account_settings_check_frequency_entries_push); 413 mCheckFrequency.setEntryValues(R.array.account_settings_check_frequency_values_push); 414 } 415 416 mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval())); 417 mCheckFrequency.setSummary(mCheckFrequency.getEntry()); 418 mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 419 public boolean onPreferenceChange(Preference preference, Object newValue) { 420 final String summary = newValue.toString(); 421 int index = mCheckFrequency.findIndexOfValue(summary); 422 mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]); 423 mCheckFrequency.setValue(summary); 424 onPreferenceChanged(); 425 return false; 426 } 427 }); 428 429 // Add check window preference 430 mSyncWindow = null; 431 if (info.mVisibleLimitDefault == -1) { 432 mSyncWindow = new ListPreference(mContext); 433 mSyncWindow.setTitle(R.string.account_setup_options_mail_window_label); 434 mSyncWindow.setEntries(R.array.account_settings_mail_window_entries); 435 mSyncWindow.setEntryValues(R.array.account_settings_mail_window_values); 436 mSyncWindow.setValue(String.valueOf(mAccount.getSyncLookback())); 437 mSyncWindow.setSummary(mSyncWindow.getEntry()); 438 mSyncWindow.setOrder(4); 439 mSyncWindow.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 440 public boolean onPreferenceChange(Preference preference, Object newValue) { 441 final String summary = newValue.toString(); 442 int index = mSyncWindow.findIndexOfValue(summary); 443 mSyncWindow.setSummary(mSyncWindow.getEntries()[index]); 444 mSyncWindow.setValue(summary); 445 onPreferenceChanged(); 446 return false; 447 } 448 }); 449 topCategory.addPreference(mSyncWindow); 450 } 451 452 // Show "background attachments" for IMAP & EAS - hide it for POP3. 453 mAccountBackgroundAttachments = (CheckBoxPreference) 454 findPreference(PREFERENCE_BACKGROUND_ATTACHMENTS); 455 if ("pop3".equals(mAccount.mHostAuthRecv.mProtocol)) { 456 topCategory.removePreference(mAccountBackgroundAttachments); 457 } else { 458 mAccountBackgroundAttachments.setChecked( 459 0 != (mAccount.getFlags() & Account.FLAGS_BACKGROUND_ATTACHMENTS)); 460 mAccountBackgroundAttachments.setOnPreferenceChangeListener(mPreferenceChangeListener); 461 } 462 463 mAccountDefault = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT); 464 mAccountDefault.setChecked(mAccount.mId == mDefaultAccountId); 465 mAccountDefault.setOnPreferenceChangeListener(mPreferenceChangeListener); 466 467 mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY); 468 mAccountNotify.setChecked(0 != (mAccount.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL)); 469 mAccountNotify.setOnPreferenceChangeListener(mPreferenceChangeListener); 470 471 mAccountRingtone = (RingtonePreference) findPreference(PREFERENCE_RINGTONE); 472 mAccountRingtone.setOnPreferenceChangeListener(mPreferenceChangeListener); 473 474 // The following two lines act as a workaround for the RingtonePreference 475 // which does not let us set/get the value programmatically 476 SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences(); 477 prefs.edit().putString(PREFERENCE_RINGTONE, mAccount.getRingtone()).apply(); 478 479 // Set the vibrator value, or hide it on devices w/o a vibrator 480 mAccountVibrateWhen = (ListPreference) findPreference(PREFERENCE_VIBRATE_WHEN); 481 Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); 482 if (vibrator.hasVibrator()) { 483 boolean flagsVibrate = 0 != (mAccount.getFlags() & Account.FLAGS_VIBRATE_ALWAYS); 484 boolean flagsVibrateSilent = 485 0 != (mAccount.getFlags() & Account.FLAGS_VIBRATE_WHEN_SILENT); 486 mAccountVibrateWhen.setValue( 487 flagsVibrate ? PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS : 488 flagsVibrateSilent ? PREFERENCE_VALUE_VIBRATE_WHEN_SILENT : 489 PREFERENCE_VALUE_VIBRATE_WHEN_NEVER); 490 mAccountVibrateWhen.setOnPreferenceChangeListener(mPreferenceChangeListener); 491 } else { 492 PreferenceCategory notificationsCategory = (PreferenceCategory) 493 findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS); 494 notificationsCategory.removePreference(mAccountVibrateWhen); 495 } 496 497 findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener( 498 new Preference.OnPreferenceClickListener() { 499 public boolean onPreferenceClick(Preference preference) { 500 mAccountDirty = true; 501 mCallback.onIncomingSettings(mAccount); 502 return true; 503 } 504 }); 505 506 // Hide the outgoing account setup link if it's not activated 507 Preference prefOutgoing = findPreference(PREFERENCE_OUTGOING); 508 boolean showOutgoing = true; 509 try { 510 Sender sender = Sender.getInstance(mContext, mAccount.getSenderUri(mContext)); 511 if (sender != null) { 512 Class<? extends android.app.Activity> setting = sender.getSettingActivityClass(); 513 showOutgoing = (setting != null); 514 } 515 } catch (MessagingException me) { 516 // just leave showOutgoing as true - bias towards showing it, so user can fix it 517 } 518 if (showOutgoing) { 519 prefOutgoing.setOnPreferenceClickListener( 520 new Preference.OnPreferenceClickListener() { 521 public boolean onPreferenceClick(Preference preference) { 522 mAccountDirty = true; 523 mCallback.onOutgoingSettings(mAccount); 524 return true; 525 } 526 }); 527 } else { 528 PreferenceCategory serverCategory = (PreferenceCategory) findPreference( 529 PREFERENCE_CATEGORY_SERVER); 530 serverCategory.removePreference(prefOutgoing); 531 } 532 533 mSyncContacts = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CONTACTS); 534 mSyncCalendar = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CALENDAR); 535 mSyncEmail = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_EMAIL); 536 if (mAccount.mHostAuthRecv.mProtocol.equals("eas")) { 537 android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress, 538 Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 539 mSyncContacts.setChecked(ContentResolver 540 .getSyncAutomatically(acct, ContactsContract.AUTHORITY)); 541 mSyncContacts.setOnPreferenceChangeListener(mPreferenceChangeListener); 542 mSyncCalendar.setChecked(ContentResolver 543 .getSyncAutomatically(acct, Calendar.AUTHORITY)); 544 mSyncCalendar.setOnPreferenceChangeListener(mPreferenceChangeListener); 545 mSyncEmail.setChecked(ContentResolver 546 .getSyncAutomatically(acct, EmailContent.AUTHORITY)); 547 mSyncEmail.setOnPreferenceChangeListener(mPreferenceChangeListener); 548 } else { 549 PreferenceCategory serverCategory = (PreferenceCategory) findPreference( 550 PREFERENCE_CATEGORY_SERVER); 551 serverCategory.removePreference(mSyncContacts); 552 serverCategory.removePreference(mSyncCalendar); 553 serverCategory.removePreference(mSyncEmail); 554 } 555 556 // Temporary home for delete account 557 Preference prefDeleteAccount = findPreference(PREFERENCE_DELETE_ACCOUNT); 558 prefDeleteAccount.setOnPreferenceClickListener( 559 new Preference.OnPreferenceClickListener() { 560 public boolean onPreferenceClick(Preference preference) { 561 DeleteAccountFragment dialogFragment = DeleteAccountFragment.newInstance( 562 mAccount, AccountSettingsFragment.this); 563 FragmentTransaction ft = getFragmentManager().beginTransaction(); 564 ft.addToBackStack(null); 565 dialogFragment.show(ft, DeleteAccountFragment.TAG); 566 return true; 567 } 568 }); 569 } 570 571 /** 572 * Generic onPreferenceChanged listener for the preferences (above) that just need 573 * to be written, without extra tweaks 574 */ 575 private Preference.OnPreferenceChangeListener mPreferenceChangeListener = 576 new Preference.OnPreferenceChangeListener() { 577 public boolean onPreferenceChange(Preference preference, Object newValue) { 578 onPreferenceChanged(); 579 return true; 580 } 581 }; 582 583 /** 584 * Called any time a preference is changed. 585 */ 586 private void onPreferenceChanged() { 587 mSaveOnExit = true; 588 } 589 590 /* 591 * Note: This writes the settings on the UI thread. This has to be done so the settings are 592 * committed before we might be killed. 593 */ 594 private void saveSettings() { 595 // Turn off all controlled flags - will turn them back on while checking UI elements 596 int newFlags = mAccount.getFlags() & 597 ~(Account.FLAGS_NOTIFY_NEW_MAIL | 598 Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_VIBRATE_WHEN_SILENT | 599 Account.FLAGS_BACKGROUND_ATTACHMENTS); 600 601 newFlags |= mAccountBackgroundAttachments.isChecked() ? 602 Account.FLAGS_BACKGROUND_ATTACHMENTS : 0; 603 mAccount.setDefaultAccount(mAccountDefault.isChecked()); 604 mAccount.setDisplayName(mAccountDescription.getText()); 605 mAccount.setSenderName(mAccountName.getText()); 606 mAccount.setSignature(mAccountSignature.getText()); 607 newFlags |= mAccountNotify.isChecked() ? Account.FLAGS_NOTIFY_NEW_MAIL : 0; 608 mAccount.setSyncInterval(Integer.parseInt(mCheckFrequency.getValue())); 609 if (mSyncWindow != null) { 610 mAccount.setSyncLookback(Integer.parseInt(mSyncWindow.getValue())); 611 } 612 if (mAccountVibrateWhen.getValue().equals(PREFERENCE_VALUE_VIBRATE_WHEN_ALWAYS)) { 613 newFlags |= Account.FLAGS_VIBRATE_ALWAYS; 614 } else if (mAccountVibrateWhen.getValue().equals(PREFERENCE_VALUE_VIBRATE_WHEN_SILENT)) { 615 newFlags |= Account.FLAGS_VIBRATE_WHEN_SILENT; 616 } 617 SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences(); 618 mAccount.setRingtone(prefs.getString(PREFERENCE_RINGTONE, null)); 619 mAccount.setFlags(newFlags); 620 621 if (mAccount.mHostAuthRecv.mProtocol.equals("eas")) { 622 android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress, 623 Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 624 ContentResolver.setSyncAutomatically(acct, ContactsContract.AUTHORITY, 625 mSyncContacts.isChecked()); 626 ContentResolver.setSyncAutomatically(acct, Calendar.AUTHORITY, 627 mSyncCalendar.isChecked()); 628 ContentResolver.setSyncAutomatically(acct, EmailContent.AUTHORITY, 629 mSyncEmail.isChecked()); 630 } 631 632 // Commit the changes 633 // Note, this is done in the UI thread because at this point, we must commit 634 // all changes - any time after onPause completes, we could be killed. This is analogous 635 // to the way that SharedPreferences tries to work off-thread in apply(), but will pause 636 // until completion in onPause(). 637 ContentValues cv = AccountSettingsUtils.getAccountContentValues(mAccount); 638 mAccount.update(mContext, cv); 639 640 // Run the remaining changes off-thread 641 Email.setServicesEnabledAsync(mContext); 642 } 643 644 /** 645 * Dialog fragment to show "remove account?" dialog 646 */ 647 public static class DeleteAccountFragment extends DialogFragment { 648 private final static String TAG = "DeleteAccountFragment"; 649 650 // Argument bundle keys 651 private final static String BUNDLE_KEY_ACCOUNT_NAME = "DeleteAccountFragment.Name"; 652 653 /** 654 * Create the dialog with parameters 655 */ 656 public static DeleteAccountFragment newInstance(Account account, Fragment parentFragment) { 657 DeleteAccountFragment f = new DeleteAccountFragment(); 658 Bundle b = new Bundle(); 659 b.putString(BUNDLE_KEY_ACCOUNT_NAME, account.getDisplayName()); 660 f.setArguments(b); 661 f.setTargetFragment(parentFragment, 0); 662 return f; 663 } 664 665 @Override 666 public Dialog onCreateDialog(Bundle savedInstanceState) { 667 Context context = getActivity(); 668 final String name = getArguments().getString(BUNDLE_KEY_ACCOUNT_NAME); 669 670 return new AlertDialog.Builder(context) 671 .setIconAttribute(android.R.attr.alertDialogIcon) 672 .setTitle(R.string.account_delete_dlg_title) 673 .setMessage(context.getString(R.string.account_delete_dlg_instructions_fmt, name)) 674 .setPositiveButton( 675 R.string.okay_action, 676 new DialogInterface.OnClickListener() { 677 public void onClick(DialogInterface dialog, int whichButton) { 678 Fragment f = getTargetFragment(); 679 if (f instanceof AccountSettingsFragment) { 680 ((AccountSettingsFragment)f).finishDeleteAccount(); 681 } 682 dismiss(); 683 } 684 }) 685 .setNegativeButton( 686 R.string.cancel_action, 687 new DialogInterface.OnClickListener() { 688 public void onClick(DialogInterface dialog, int whichButton) { 689 dismiss(); 690 } 691 }) 692 .create(); 693 } 694 } 695 696 /** 697 * Callback from delete account dialog - passes the delete command up to the activity 698 */ 699 private void finishDeleteAccount() { 700 mSaveOnExit = false; 701 mCallback.deleteAccount(mAccount); 702 } 703} 704