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