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