• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getMetricsCategory()137     protected int getMetricsCategory() {
138         return MetricsEvent.ACCOUNT;
139     }
140 
141     @Override
onCreate(Bundle savedInstanceState)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
onCreateOptionsMenu(Menu menu, MenuInflater inflater)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
onPrepareOptionsMenu(Menu menu)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
onResume()191     public void onResume() {
192         super.onResume();
193         cleanUpPreferences();
194         updateUi();
195         mManagedProfileBroadcastReceiver.register(getActivity());
196         listenToAccountUpdates();
197     }
198 
199     @Override
onPause()200     public void onPause() {
201         super.onPause();
202         stopListeningToAccountUpdates();
203         mManagedProfileBroadcastReceiver.unregister(getActivity());
204     }
205 
206     @Override
onAccountsUpdate(UserHandle userHandle)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
onPreferenceClick(Preference preference)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 
updateUi()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 
updateProfileUi(final UserInfo userInfo, boolean addCategory, PreferenceScreen parent)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 
newAddAccountPreference(Context context)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 
newRemoveWorkProfilePreference(Context context)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 
newManagedProfileSettings()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 
getWorkGroupSummary(Context context, UserInfo userInfo)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 
cleanUpPreferences()371     private void cleanUpPreferences() {
372         PreferenceScreen preferenceScreen = getPreferenceScreen();
373         if (preferenceScreen != null) {
374             preferenceScreen.removeAll();
375         }
376         mProfiles.clear();
377     }
378 
listenToAccountUpdates()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 
stopListeningToAccountUpdates()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 
updateAccountTypes(ProfileData profileData)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 
getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle)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 
accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)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 
AccountPreference(Context context, CharSequence title, String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments, Drawable icon)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
onPreferenceClick(Preference preference)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
onReceive(Context context, Intent intent)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 
register(Context context)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 
unregister(Context context)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 
MasterSyncStateClickListener(UserHandle userHandle)610         public MasterSyncStateClickListener(UserHandle userHandle) {
611             mUserHandle = userHandle;
612         }
613 
614         @Override
onMenuItemClick(MenuItem item)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 
show(AccountSettings parent, boolean enabling, UserHandle userHandle)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
onCreateDialog(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)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