1 /*
2  * Copyright (C) 2014 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 
17 package com.android.settings.accounts;
18 
19 
20 import android.accounts.Account;
21 import android.accounts.AccountManager;
22 import android.app.ActivityManager;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.app.DialogFragment;
26 import android.content.BroadcastReceiver;
27 import android.content.ContentResolver;
28 import android.content.Context;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.UserInfo;
33 import android.graphics.drawable.Drawable;
34 import android.os.Bundle;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.os.Process;
38 import android.util.Log;
39 import android.util.SparseArray;
40 import android.view.Menu;
41 import android.view.MenuInflater;
42 import android.view.MenuItem;
43 import android.preference.Preference;
44 import android.preference.Preference.OnPreferenceClickListener;
45 import android.preference.PreferenceGroup;
46 import android.preference.PreferenceCategory;
47 import android.preference.PreferenceScreen;
48 
49 import com.android.settings.R;
50 import com.android.settings.SettingsPreferenceFragment;
51 import com.android.settings.Utils;
52 
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.Comparator;
56 import java.util.List;
57 
58 import static android.content.Intent.EXTRA_USER;
59 import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
60 import static android.provider.Settings.EXTRA_AUTHORITIES;
61 
62 /**
63  * Settings screen for the account types on the device.
64  * This shows all account types available for personal and work profiles.
65  *
66  * An extra {@link UserHandle} can be specified in the intent as {@link EXTRA_USER}, if the user for
67  * which the action needs to be performed is different to the one the Settings App will run in.
68  */
69 public class AccountSettings extends SettingsPreferenceFragment
70         implements AuthenticatorHelper.OnAccountsUpdateListener,
71         OnPreferenceClickListener {
72     public static final String TAG = "AccountSettings";
73 
74     private static final String KEY_ACCOUNT = "account";
75 
76     private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS";
77     private static final String TAG_CONFIRM_AUTO_SYNC_CHANGE = "confirmAutoSyncChange";
78 
79     private static final int ORDER_LAST = 1001;
80     private static final int ORDER_NEXT_TO_LAST = 1000;
81 
82     private UserManager mUm;
83     private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
84     private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver
85                 = new ManagedProfileBroadcastReceiver();
86     private Preference mProfileNotAvailablePreference;
87     private String[] mAuthorities;
88     private int mAuthoritiesCount = 0;
89 
90     /**
91      * Holds data related to the accounts belonging to one profile.
92      */
93     private static class ProfileData {
94         /**
95          * The preference that displays the accounts.
96          */
97         public PreferenceGroup preferenceGroup;
98         /**
99          * The preference that displays the add account button.
100          */
101         public Preference addAccountPreference;
102         /**
103          * The preference that displays the button to remove the managed profile
104          */
105         public Preference removeWorkProfilePreference;
106         /**
107          * The {@link AuthenticatorHelper} that holds accounts data for this profile.
108          */
109         public AuthenticatorHelper authenticatorHelper;
110         /**
111          * The {@link UserInfo} of the profile.
112          */
113         public UserInfo userInfo;
114     }
115 
116     @Override
onCreate(Bundle savedInstanceState)117     public void onCreate(Bundle savedInstanceState) {
118         super.onCreate(savedInstanceState);
119         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
120         mProfileNotAvailablePreference = new Preference(getActivity());
121         mAuthorities = getActivity().getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
122         if (mAuthorities != null) {
123             mAuthoritiesCount = mAuthorities.length;
124         }
125         setHasOptionsMenu(true);
126     }
127 
128     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)129     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
130         inflater.inflate(R.menu.account_settings, menu);
131         super.onCreateOptionsMenu(menu, inflater);
132     }
133 
134     @Override
onPrepareOptionsMenu(Menu menu)135     public void onPrepareOptionsMenu(Menu menu) {
136         final UserHandle currentProfile = Process.myUserHandle();
137         if (mProfiles.size() == 1) {
138             menu.findItem(R.id.account_settings_menu_auto_sync)
139                     .setVisible(true)
140                     .setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
141                     .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
142                             currentProfile.getIdentifier()));
143             menu.findItem(R.id.account_settings_menu_auto_sync_personal).setVisible(false);
144             menu.findItem(R.id.account_settings_menu_auto_sync_work).setVisible(false);
145         } else if (mProfiles.size() > 1) {
146             // We assume there's only one managed profile, otherwise UI needs to change
147             final UserHandle managedProfile = mProfiles.valueAt(1).userInfo.getUserHandle();
148 
149             menu.findItem(R.id.account_settings_menu_auto_sync_personal)
150                     .setVisible(true)
151                     .setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
152                     .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
153                             currentProfile.getIdentifier()));
154             menu.findItem(R.id.account_settings_menu_auto_sync_work)
155                     .setVisible(true)
156                     .setOnMenuItemClickListener(new MasterSyncStateClickListener(managedProfile))
157                     .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
158                             managedProfile.getIdentifier()));
159             menu.findItem(R.id.account_settings_menu_auto_sync).setVisible(false);
160          } else {
161              Log.w(TAG, "Method onPrepareOptionsMenu called before mProfiles was initialized");
162          }
163     }
164 
165     @Override
onResume()166     public void onResume() {
167         super.onResume();
168         updateUi();
169         mManagedProfileBroadcastReceiver.register(getActivity());
170         listenToAccountUpdates();
171     }
172 
173     @Override
onPause()174     public void onPause() {
175         super.onPause();
176         stopListeningToAccountUpdates();
177         mManagedProfileBroadcastReceiver.unregister(getActivity());
178         cleanUpPreferences();
179     }
180 
181     @Override
onAccountsUpdate(UserHandle userHandle)182     public void onAccountsUpdate(UserHandle userHandle) {
183         final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
184         if (profileData != null) {
185             updateAccountTypes(profileData);
186         } else {
187             Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
188         }
189     }
190 
191     @Override
onPreferenceClick(Preference preference)192     public boolean onPreferenceClick(Preference preference) {
193         // Check the preference
194         final int count = mProfiles.size();
195         for (int i = 0; i < count; i++) {
196             ProfileData profileData = mProfiles.valueAt(i);
197             if (preference == profileData.addAccountPreference) {
198                 Intent intent = new Intent(ADD_ACCOUNT_ACTION);
199                 intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
200                 intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
201                 startActivity(intent);
202                 return true;
203             }
204             if (preference == profileData.removeWorkProfilePreference) {
205                 final int userId = profileData.userInfo.id;
206                 Utils.createRemoveConfirmationDialog(getActivity(), userId,
207                         new DialogInterface.OnClickListener() {
208                             @Override
209                             public void onClick(DialogInterface dialog, int which) {
210                                 mUm.removeUser(userId);
211                             }
212                         }
213                 ).show();
214                 return true;
215             }
216         }
217         return false;
218     }
219 
updateUi()220     void updateUi() {
221         // Load the preferences from an XML resource
222         addPreferencesFromResource(R.xml.account_settings);
223 
224         if (Utils.isManagedProfile(mUm)) {
225             // This should not happen
226             Log.e(TAG, "We should not be showing settings for a managed profile");
227             finish();
228             return;
229         }
230 
231         final PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference(KEY_ACCOUNT);
232         if(mUm.isLinkedUser()) {
233             // Restricted user or similar
234             UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
235             updateProfileUi(userInfo, false /* no category needed */, preferenceScreen);
236         } else {
237             List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
238             final int profilesCount = profiles.size();
239             final boolean addCategory = profilesCount > 1;
240             for (int i = 0; i < profilesCount; i++) {
241                 updateProfileUi(profiles.get(i), addCategory, preferenceScreen);
242             }
243         }
244 
245         // Add all preferences, starting with one for the primary profile.
246         // Note that we're relying on the ordering given by the SparseArray keys, and on the
247         // value of UserHandle.USER_OWNER being smaller than all the rest.
248         final int profilesCount = mProfiles.size();
249         for (int i = 0; i < profilesCount; i++) {
250             ProfileData profileData = mProfiles.valueAt(i);
251             if (!profileData.preferenceGroup.equals(preferenceScreen)) {
252                 preferenceScreen.addPreference(profileData.preferenceGroup);
253             }
254             updateAccountTypes(profileData);
255         }
256     }
257 
updateProfileUi(final UserInfo userInfo, boolean addCategory, PreferenceScreen parent)258     private void updateProfileUi(final UserInfo userInfo, boolean addCategory,
259             PreferenceScreen parent) {
260         final Context context = getActivity();
261         final ProfileData profileData = new ProfileData();
262         profileData.userInfo = userInfo;
263         if (addCategory) {
264             profileData.preferenceGroup = new PreferenceCategory(context);
265             profileData.preferenceGroup.setTitle(userInfo.isManagedProfile()
266                     ? R.string.category_work : R.string.category_personal);
267             parent.addPreference(profileData.preferenceGroup);
268         } else {
269             profileData.preferenceGroup = parent;
270         }
271         if (userInfo.isEnabled()) {
272             profileData.authenticatorHelper = new AuthenticatorHelper(context,
273                     userInfo.getUserHandle(), mUm, this);
274             if (!mUm.hasUserRestriction(DISALLOW_MODIFY_ACCOUNTS, userInfo.getUserHandle())) {
275                 profileData.addAccountPreference = newAddAccountPreference(context);
276             }
277         }
278         if (userInfo.isManagedProfile()) {
279             profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference(context);
280         }
281         mProfiles.put(userInfo.id, profileData);
282     }
283 
newAddAccountPreference(Context context)284     private Preference newAddAccountPreference(Context context) {
285         Preference preference = new Preference(context);
286         preference.setTitle(R.string.add_account_label);
287         preference.setIcon(R.drawable.ic_menu_add_dark);
288         preference.setOnPreferenceClickListener(this);
289         preference.setOrder(ORDER_NEXT_TO_LAST);
290         return preference;
291     }
292 
newRemoveWorkProfilePreference(Context context)293     private Preference newRemoveWorkProfilePreference(Context context) {
294         Preference preference = new Preference(context);
295         preference.setTitle(R.string.remove_managed_profile_label);
296         preference.setIcon(R.drawable.ic_menu_delete);
297         preference.setOnPreferenceClickListener(this);
298         preference.setOrder(ORDER_LAST);
299         return preference;
300     }
301 
cleanUpPreferences()302     private void cleanUpPreferences() {
303         PreferenceScreen preferenceScreen = getPreferenceScreen();
304         if (preferenceScreen != null) {
305             preferenceScreen.removeAll();
306         }
307         mProfiles.clear();
308     }
309 
listenToAccountUpdates()310     private void listenToAccountUpdates() {
311         final int count = mProfiles.size();
312         for (int i = 0; i < count; i++) {
313             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
314             if (authenticatorHelper != null) {
315                 authenticatorHelper.listenToAccountUpdates();
316             }
317         }
318     }
319 
stopListeningToAccountUpdates()320     private void stopListeningToAccountUpdates() {
321         final int count = mProfiles.size();
322         for (int i = 0; i < count; i++) {
323             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
324             if (authenticatorHelper != null) {
325                 authenticatorHelper.stopListeningToAccountUpdates();
326             }
327         }
328     }
329 
updateAccountTypes(ProfileData profileData)330     private void updateAccountTypes(ProfileData profileData) {
331         profileData.preferenceGroup.removeAll();
332         if (profileData.userInfo.isEnabled()) {
333             final ArrayList<AccountPreference> preferences = getAccountTypePreferences(
334                     profileData.authenticatorHelper, profileData.userInfo.getUserHandle());
335             final int count = preferences.size();
336             for (int i = 0; i < count; i++) {
337                 profileData.preferenceGroup.addPreference(preferences.get(i));
338             }
339             if (profileData.addAccountPreference != null) {
340                 profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
341             }
342         } else {
343             // Put a label instead of the accounts list
344             mProfileNotAvailablePreference.setEnabled(false);
345             mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
346             mProfileNotAvailablePreference.setTitle(null);
347             mProfileNotAvailablePreference.setSummary(
348                     R.string.managed_profile_not_available_label);
349             profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
350         }
351         if (profileData.removeWorkProfilePreference != null) {
352             profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
353         }
354     }
355 
getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle)356     private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper,
357             UserHandle userHandle) {
358         final String[] accountTypes = helper.getEnabledAccountTypes();
359         final ArrayList<AccountPreference> accountTypePreferences =
360                 new ArrayList<AccountPreference>(accountTypes.length);
361 
362         for (int i = 0; i < accountTypes.length; i++) {
363             final String accountType = accountTypes[i];
364             // Skip showing any account that does not have any of the requested authorities
365             if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
366                 continue;
367             }
368             final CharSequence label = helper.getLabelForType(getActivity(), accountType);
369             if (label == null) {
370                 continue;
371             }
372             final String titleResPackageName = helper.getPackageForType(accountType);
373             final int titleResId = helper.getLabelIdForType(accountType);
374 
375             final Account[] accounts = AccountManager.get(getActivity())
376                     .getAccountsByTypeAsUser(accountType, userHandle);
377             final boolean skipToAccount = accounts.length == 1
378                     && !helper.hasAccountPreferences(accountType);
379 
380             if (skipToAccount) {
381                 final Bundle fragmentArguments = new Bundle();
382                 fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
383                         accounts[0]);
384                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
385 
386                 accountTypePreferences.add(new AccountPreference(getActivity(), label,
387                         titleResPackageName, titleResId, AccountSyncSettings.class.getName(),
388                         fragmentArguments,
389                         helper.getDrawableForType(getActivity(), accountType)));
390             } else {
391                 final Bundle fragmentArguments = new Bundle();
392                 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
393                 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
394                         label.toString());
395                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
396 
397                 accountTypePreferences.add(new AccountPreference(getActivity(), label,
398                         titleResPackageName, titleResId, ManageAccountsSettings.class.getName(),
399                         fragmentArguments,
400                         helper.getDrawableForType(getActivity(), accountType)));
401             }
402             helper.preloadDrawableForType(getActivity(), accountType);
403         }
404         // Sort by label
405         Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() {
406             @Override
407             public int compare(AccountPreference t1, AccountPreference t2) {
408                 return t1.mTitle.toString().compareTo(t2.mTitle.toString());
409             }
410         });
411         return accountTypePreferences;
412     }
413 
accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)414     private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
415             String accountType) {
416         if (mAuthoritiesCount == 0) {
417             // No authorities required
418             return true;
419         }
420         final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
421                 accountType);
422         if (authoritiesForType == null) {
423             Log.d(TAG, "No sync authorities for account type: " + accountType);
424             return false;
425         }
426         for (int j = 0; j < mAuthoritiesCount; j++) {
427             if (authoritiesForType.contains(mAuthorities[j])) {
428                 return true;
429             }
430         }
431         return false;
432     }
433 
434     private class AccountPreference extends Preference implements OnPreferenceClickListener {
435         /**
436          * Title of the tile that is shown to the user.
437          * @attr ref android.R.styleable#PreferenceHeader_title
438          */
439         private final CharSequence mTitle;
440 
441         /**
442          * Packange name used to resolve the resources of the title shown to the user in the new
443          * fragment.
444          */
445         private final String mTitleResPackageName;
446 
447         /**
448          * Resource id of the title shown to the user in the new fragment.
449          */
450         private final int mTitleResId;
451 
452         /**
453          * Full class name of the fragment to display when this tile is
454          * selected.
455          * @attr ref android.R.styleable#PreferenceHeader_fragment
456          */
457         private final String mFragment;
458 
459         /**
460          * Optional arguments to supply to the fragment when it is
461          * instantiated.
462          */
463         private final Bundle mFragmentArguments;
464 
AccountPreference(Context context, CharSequence title, String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments, Drawable icon)465         public AccountPreference(Context context, CharSequence title, String titleResPackageName,
466                 int titleResId, String fragment, Bundle fragmentArguments,
467                 Drawable icon) {
468             super(context);
469             mTitle = title;
470             mTitleResPackageName = titleResPackageName;
471             mTitleResId = titleResId;
472             mFragment = fragment;
473             mFragmentArguments = fragmentArguments;
474             setWidgetLayoutResource(R.layout.account_type_preference);
475 
476             setTitle(title);
477             setIcon(icon);
478 
479             setOnPreferenceClickListener(this);
480         }
481 
482         @Override
onPreferenceClick(Preference preference)483         public boolean onPreferenceClick(Preference preference) {
484             if (mFragment != null) {
485                 Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
486                         null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
487                         mTitleResId, null /* title */);
488                 return true;
489             }
490             return false;
491         }
492     }
493 
494     private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
495         private boolean listeningToManagedProfileEvents;
496 
497         @Override
onReceive(Context context, Intent intent)498         public void onReceive(Context context, Intent intent) {
499             if (intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
500                     || intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
501                 Log.v(TAG, "Received broadcast: " + intent.getAction());
502                 // Clean old state
503                 stopListeningToAccountUpdates();
504                 cleanUpPreferences();
505                 // Build new state
506                 updateUi();
507                 listenToAccountUpdates();
508                 // Force the menu to update. Note that #onPrepareOptionsMenu uses data built by
509                 // #updateUi so we must call this later
510                 getActivity().invalidateOptionsMenu();
511                 return;
512             }
513             Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
514         }
515 
register(Context context)516         public void register(Context context) {
517             if (!listeningToManagedProfileEvents) {
518                 IntentFilter intentFilter = new IntentFilter();
519                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
520                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
521                 context.registerReceiver(this, intentFilter);
522                 listeningToManagedProfileEvents = true;
523             }
524         }
525 
unregister(Context context)526         public void unregister(Context context) {
527             if (listeningToManagedProfileEvents) {
528                 context.unregisterReceiver(this);
529                 listeningToManagedProfileEvents = false;
530             }
531         }
532     }
533 
534     private class MasterSyncStateClickListener implements MenuItem.OnMenuItemClickListener {
535         private final UserHandle mUserHandle;
536 
MasterSyncStateClickListener(UserHandle userHandle)537         public MasterSyncStateClickListener(UserHandle userHandle) {
538             mUserHandle = userHandle;
539         }
540 
541         @Override
onMenuItemClick(MenuItem item)542         public boolean onMenuItemClick(MenuItem item) {
543             if (ActivityManager.isUserAMonkey()) {
544                 Log.d(TAG, "ignoring monkey's attempt to flip sync state");
545             } else {
546                 ConfirmAutoSyncChangeFragment.show(AccountSettings.this, !item.isChecked(),
547                         mUserHandle);
548             }
549             return true;
550         }
551     }
552 
553     /**
554      * Dialog to inform user about changing auto-sync setting
555      */
556     public static class ConfirmAutoSyncChangeFragment extends DialogFragment {
557         private static final String SAVE_ENABLING = "enabling";
558         private static final String SAVE_USER_HANDLE = "userHandle";
559         private boolean mEnabling;
560         private UserHandle mUserHandle;
561 
show(AccountSettings parent, boolean enabling, UserHandle userHandle)562         public static void show(AccountSettings parent, boolean enabling, UserHandle userHandle) {
563             if (!parent.isAdded()) return;
564 
565             final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment();
566             dialog.mEnabling = enabling;
567             dialog.mUserHandle = userHandle;
568             dialog.setTargetFragment(parent, 0);
569             dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE);
570         }
571 
572         @Override
onCreateDialog(Bundle savedInstanceState)573         public Dialog onCreateDialog(Bundle savedInstanceState) {
574             final Context context = getActivity();
575             if (savedInstanceState != null) {
576                 mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING);
577                 mUserHandle = (UserHandle) savedInstanceState.getParcelable(SAVE_USER_HANDLE);
578             }
579 
580             final AlertDialog.Builder builder = new AlertDialog.Builder(context);
581             if (!mEnabling) {
582                 builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title);
583                 builder.setMessage(R.string.data_usage_auto_sync_off_dialog);
584             } else {
585                 builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title);
586                 builder.setMessage(R.string.data_usage_auto_sync_on_dialog);
587             }
588 
589             builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
590                 @Override
591                 public void onClick(DialogInterface dialog, int which) {
592                     ContentResolver.setMasterSyncAutomaticallyAsUser(mEnabling,
593                             mUserHandle.getIdentifier());
594                 }
595             });
596             builder.setNegativeButton(android.R.string.cancel, null);
597 
598             return builder.create();
599         }
600 
601         @Override
onSaveInstanceState(Bundle outState)602         public void onSaveInstanceState(Bundle outState) {
603             super.onSaveInstanceState(outState);
604             outState.putBoolean(SAVE_ENABLING, mEnabling);
605             outState.putParcelable(SAVE_USER_HANDLE, mUserHandle);
606         }
607     }
608     // TODO Implement a {@link SearchIndexProvider} to allow Indexing and Search of account types
609     // See http://b/15403806
610 }
611