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