Home | History | Annotate | Download | only in accounts
      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
    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
    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
    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
    166     public void onResume() {
    167         super.onResume();
    168         updateUi();
    169         mManagedProfileBroadcastReceiver.register(getActivity());
    170         listenToAccountUpdates();
    171     }
    172 
    173     @Override
    174     public void onPause() {
    175         super.onPause();
    176         stopListeningToAccountUpdates();
    177         mManagedProfileBroadcastReceiver.unregister(getActivity());
    178         cleanUpPreferences();
    179     }
    180 
    181     @Override
    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
    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 
    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 
    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 
    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 
    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 
    302     private void cleanUpPreferences() {
    303         PreferenceScreen preferenceScreen = getPreferenceScreen();
    304         if (preferenceScreen != null) {
    305             preferenceScreen.removeAll();
    306         }
    307         mProfiles.clear();
    308     }
    309 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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 
    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 
    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 
    537         public MasterSyncStateClickListener(UserHandle userHandle) {
    538             mUserHandle = userHandle;
    539         }
    540 
    541         @Override
    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 
    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
    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
    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