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