• 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             if (!RestrictedLockUtils.hasBaseUserRestriction(context,
320                     UserManager.DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) {
321                 profileData.addAccountPreference = newAddAccountPreference(context);
322                 profileData.addAccountPreference.checkRestrictionAndSetDisabled(
323                         DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
324             }
325         }
326         mProfiles.put(userInfo.id, profileData);
327         Index.getInstance(getActivity()).updateFromClassNameResource(
328                 AccountSettings.class.getName(), true, true);
329     }
330 
newAddAccountPreference(Context context)331     private DimmableIconPreference newAddAccountPreference(Context context) {
332         DimmableIconPreference preference = new DimmableIconPreference(getPrefContext());
333         preference.setTitle(R.string.add_account_label);
334         preference.setIcon(R.drawable.ic_menu_add);
335         preference.setOnPreferenceClickListener(this);
336         preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
337         return preference;
338     }
339 
newRemoveWorkProfilePreference(Context context)340     private Preference newRemoveWorkProfilePreference(Context context) {
341         Preference preference = new Preference(getPrefContext());
342         preference.setTitle(R.string.remove_managed_profile_label);
343         preference.setIcon(R.drawable.ic_menu_delete);
344         preference.setOnPreferenceClickListener(this);
345         preference.setOrder(ORDER_LAST);
346         return preference;
347     }
348 
349 
newManagedProfileSettings()350     private Preference newManagedProfileSettings() {
351         Preference preference = new Preference(getPrefContext());
352         preference.setTitle(R.string.managed_profile_settings_title);
353         preference.setIcon(R.drawable.ic_sysbar_quicksettings);
354         preference.setOnPreferenceClickListener(this);
355         preference.setOrder(ORDER_NEXT_TO_LAST);
356         return preference;
357     }
358 
getWorkGroupSummary(Context context, UserInfo userInfo)359     private String getWorkGroupSummary(Context context, UserInfo userInfo) {
360         PackageManager packageManager = context.getPackageManager();
361         ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
362         if (adminApplicationInfo == null) {
363             return null;
364         }
365         CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
366         return getString(R.string.managing_admin, appLabel);
367     }
368 
cleanUpPreferences()369     private void cleanUpPreferences() {
370         PreferenceScreen preferenceScreen = getPreferenceScreen();
371         if (preferenceScreen != null) {
372             preferenceScreen.removeAll();
373         }
374         mProfiles.clear();
375     }
376 
listenToAccountUpdates()377     private void listenToAccountUpdates() {
378         final int count = mProfiles.size();
379         for (int i = 0; i < count; i++) {
380             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
381             if (authenticatorHelper != null) {
382                 authenticatorHelper.listenToAccountUpdates();
383             }
384         }
385     }
386 
stopListeningToAccountUpdates()387     private void stopListeningToAccountUpdates() {
388         final int count = mProfiles.size();
389         for (int i = 0; i < count; i++) {
390             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
391             if (authenticatorHelper != null) {
392                 authenticatorHelper.stopListeningToAccountUpdates();
393             }
394         }
395     }
396 
updateAccountTypes(ProfileData profileData)397     private void updateAccountTypes(ProfileData profileData) {
398         profileData.preferenceGroup.removeAll();
399         if (profileData.userInfo.isEnabled()) {
400             final ArrayList<AccountPreference> preferences = getAccountTypePreferences(
401                     profileData.authenticatorHelper, profileData.userInfo.getUserHandle());
402             final int count = preferences.size();
403             for (int i = 0; i < count; i++) {
404                 profileData.preferenceGroup.addPreference(preferences.get(i));
405             }
406             if (profileData.addAccountPreference != null) {
407                 profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
408             }
409         } else {
410             // Put a label instead of the accounts list
411             mProfileNotAvailablePreference.setEnabled(false);
412             mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
413             mProfileNotAvailablePreference.setTitle(null);
414             mProfileNotAvailablePreference.setSummary(
415                     R.string.managed_profile_not_available_label);
416             profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
417         }
418         if (profileData.removeWorkProfilePreference != null) {
419             profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
420         }
421         if (profileData.managedProfilePreference != null) {
422             profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
423         }
424     }
425 
getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle)426     private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper,
427             UserHandle userHandle) {
428         final String[] accountTypes = helper.getEnabledAccountTypes();
429         final ArrayList<AccountPreference> accountTypePreferences =
430                 new ArrayList<AccountPreference>(accountTypes.length);
431 
432         for (int i = 0; i < accountTypes.length; i++) {
433             final String accountType = accountTypes[i];
434             // Skip showing any account that does not have any of the requested authorities
435             if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
436                 continue;
437             }
438             final CharSequence label = helper.getLabelForType(getActivity(), accountType);
439             if (label == null) {
440                 continue;
441             }
442             final String titleResPackageName = helper.getPackageForType(accountType);
443             final int titleResId = helper.getLabelIdForType(accountType);
444 
445             final Account[] accounts = AccountManager.get(getActivity())
446                     .getAccountsByTypeAsUser(accountType, userHandle);
447             final boolean skipToAccount = accounts.length == 1
448                     && !helper.hasAccountPreferences(accountType);
449 
450             if (skipToAccount) {
451                 final Bundle fragmentArguments = new Bundle();
452                 fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
453                         accounts[0]);
454                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
455 
456                 accountTypePreferences.add(new AccountPreference(getPrefContext(), label,
457                         titleResPackageName, titleResId, AccountSyncSettings.class.getName(),
458                         fragmentArguments,
459                         helper.getDrawableForType(getActivity(), accountType)));
460             } else {
461                 final Bundle fragmentArguments = new Bundle();
462                 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
463                 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
464                         label.toString());
465                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
466 
467                 accountTypePreferences.add(new AccountPreference(getPrefContext(), label,
468                         titleResPackageName, titleResId, ManageAccountsSettings.class.getName(),
469                         fragmentArguments,
470                         helper.getDrawableForType(getActivity(), accountType)));
471             }
472             helper.preloadDrawableForType(getActivity(), accountType);
473         }
474         // Sort by label
475         Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() {
476             @Override
477             public int compare(AccountPreference t1, AccountPreference t2) {
478                 return t1.mTitle.toString().compareTo(t2.mTitle.toString());
479             }
480         });
481         return accountTypePreferences;
482     }
483 
accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)484     private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
485             String accountType) {
486         if (mAuthoritiesCount == 0) {
487             // No authorities required
488             return true;
489         }
490         final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
491                 accountType);
492         if (authoritiesForType == null) {
493             Log.d(TAG, "No sync authorities for account type: " + accountType);
494             return false;
495         }
496         for (int j = 0; j < mAuthoritiesCount; j++) {
497             if (authoritiesForType.contains(mAuthorities[j])) {
498                 return true;
499             }
500         }
501         return false;
502     }
503 
504     private class AccountPreference extends Preference implements OnPreferenceClickListener {
505         /**
506          * Title of the tile that is shown to the user.
507          * @attr ref android.R.styleable#PreferenceHeader_title
508          */
509         private final CharSequence mTitle;
510 
511         /**
512          * Packange name used to resolve the resources of the title shown to the user in the new
513          * fragment.
514          */
515         private final String mTitleResPackageName;
516 
517         /**
518          * Resource id of the title shown to the user in the new fragment.
519          */
520         private final int mTitleResId;
521 
522         /**
523          * Full class name of the fragment to display when this tile is
524          * selected.
525          * @attr ref android.R.styleable#PreferenceHeader_fragment
526          */
527         private final String mFragment;
528 
529         /**
530          * Optional arguments to supply to the fragment when it is
531          * instantiated.
532          */
533         private final Bundle mFragmentArguments;
534 
AccountPreference(Context context, CharSequence title, String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments, Drawable icon)535         public AccountPreference(Context context, CharSequence title, String titleResPackageName,
536                 int titleResId, String fragment, Bundle fragmentArguments,
537                 Drawable icon) {
538             super(context);
539             mTitle = title;
540             mTitleResPackageName = titleResPackageName;
541             mTitleResId = titleResId;
542             mFragment = fragment;
543             mFragmentArguments = fragmentArguments;
544             setWidgetLayoutResource(R.layout.account_type_preference);
545 
546             setTitle(title);
547             setIcon(icon);
548 
549             setOnPreferenceClickListener(this);
550         }
551 
552         @Override
onPreferenceClick(Preference preference)553         public boolean onPreferenceClick(Preference preference) {
554             if (mFragment != null) {
555                 Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
556                         null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
557                         mTitleResId, null /* title */);
558                 return true;
559             }
560             return false;
561         }
562     }
563 
564     private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
565         private boolean listeningToManagedProfileEvents;
566 
567         @Override
onReceive(Context context, Intent intent)568         public void onReceive(Context context, Intent intent) {
569             final String action = intent.getAction();
570             Log.v(TAG, "Received broadcast: " + action);
571             if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
572                     || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
573                 // Clean old state
574                 stopListeningToAccountUpdates();
575                 cleanUpPreferences();
576                 // Build new state
577                 updateUi();
578                 listenToAccountUpdates();
579                 // Force the menu to update. Note that #onPrepareOptionsMenu uses data built by
580                 // #updateUi so we must call this later
581                 getActivity().invalidateOptionsMenu();
582                 return;
583             }
584             Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
585         }
586 
register(Context context)587         public void register(Context context) {
588             if (!listeningToManagedProfileEvents) {
589                 IntentFilter intentFilter = new IntentFilter();
590                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
591                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
592                 context.registerReceiver(this, intentFilter);
593                 listeningToManagedProfileEvents = true;
594             }
595         }
596 
unregister(Context context)597         public void unregister(Context context) {
598             if (listeningToManagedProfileEvents) {
599                 context.unregisterReceiver(this);
600                 listeningToManagedProfileEvents = false;
601             }
602         }
603     }
604 
605     private class MasterSyncStateClickListener implements MenuItem.OnMenuItemClickListener {
606         private final UserHandle mUserHandle;
607 
MasterSyncStateClickListener(UserHandle userHandle)608         public MasterSyncStateClickListener(UserHandle userHandle) {
609             mUserHandle = userHandle;
610         }
611 
612         @Override
onMenuItemClick(MenuItem item)613         public boolean onMenuItemClick(MenuItem item) {
614             if (ActivityManager.isUserAMonkey()) {
615                 Log.d(TAG, "ignoring monkey's attempt to flip sync state");
616             } else {
617                 ConfirmAutoSyncChangeFragment.show(AccountSettings.this, !item.isChecked(),
618                         mUserHandle);
619             }
620             return true;
621         }
622     }
623 
624     /**
625      * Dialog to inform user about changing auto-sync setting
626      */
627     public static class ConfirmAutoSyncChangeFragment extends DialogFragment {
628         private static final String SAVE_ENABLING = "enabling";
629         private static final String SAVE_USER_HANDLE = "userHandle";
630         private boolean mEnabling;
631         private UserHandle mUserHandle;
632 
show(AccountSettings parent, boolean enabling, UserHandle userHandle)633         public static void show(AccountSettings parent, boolean enabling, UserHandle userHandle) {
634             if (!parent.isAdded()) return;
635 
636             final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment();
637             dialog.mEnabling = enabling;
638             dialog.mUserHandle = userHandle;
639             dialog.setTargetFragment(parent, 0);
640             dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE);
641         }
642 
643         @Override
onCreateDialog(Bundle savedInstanceState)644         public Dialog onCreateDialog(Bundle savedInstanceState) {
645             final Context context = getActivity();
646             if (savedInstanceState != null) {
647                 mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING);
648                 mUserHandle = (UserHandle) savedInstanceState.getParcelable(SAVE_USER_HANDLE);
649             }
650 
651             final AlertDialog.Builder builder = new AlertDialog.Builder(context);
652             if (!mEnabling) {
653                 builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title);
654                 builder.setMessage(R.string.data_usage_auto_sync_off_dialog);
655             } else {
656                 builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title);
657                 builder.setMessage(R.string.data_usage_auto_sync_on_dialog);
658             }
659 
660             builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
661                 @Override
662                 public void onClick(DialogInterface dialog, int which) {
663                     ContentResolver.setMasterSyncAutomaticallyAsUser(mEnabling,
664                             mUserHandle.getIdentifier());
665                 }
666             });
667             builder.setNegativeButton(android.R.string.cancel, null);
668 
669             return builder.create();
670         }
671 
672         @Override
onSaveInstanceState(Bundle outState)673         public void onSaveInstanceState(Bundle outState) {
674             super.onSaveInstanceState(outState);
675             outState.putBoolean(SAVE_ENABLING, mEnabling);
676             outState.putParcelable(SAVE_USER_HANDLE, mUserHandle);
677         }
678     }
679 
680     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
681             new BaseSearchIndexProvider() {
682         @Override
683         public List<SearchIndexableResource> getXmlResourcesToIndex(
684                 Context context, boolean enabled) {
685             final SearchIndexableResource sir = new SearchIndexableResource(context);
686             sir.xmlResId = R.xml.account_settings;
687             return Arrays.asList(sir);
688         }
689 
690         @Override
691         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
692             final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
693             final Resources res = context.getResources();
694             final String screenTitle = res.getString(R.string.account_settings_title);
695 
696             final UserManager um = UserManager.get(context);
697             List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId());
698             final int profilesCount = profiles.size();
699             for (int i = 0; i < profilesCount; i++) {
700                 UserInfo userInfo = profiles.get(i);
701                 if (userInfo.isEnabled()) {
702                     if (!RestrictedLockUtils.hasBaseUserRestriction(context,
703                             DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) {
704                         SearchIndexableRaw data = new SearchIndexableRaw(context);
705                         data.title = res.getString(R.string.add_account_label);
706                         data.screenTitle = screenTitle;
707                         result.add(data);
708                     }
709                     if (userInfo.isManagedProfile()) {
710                         {
711                             SearchIndexableRaw data = new SearchIndexableRaw(context);
712                             data.title = res.getString(R.string.remove_managed_profile_label);
713                             data.screenTitle = screenTitle;
714                             result.add(data);
715                         }
716                         {
717                             SearchIndexableRaw data = new SearchIndexableRaw(context);
718                             data.title = res.getString(R.string.managed_profile_settings_title);
719                             data.screenTitle = screenTitle;
720                             result.add(data);
721                         }
722                     }
723                 }
724             }
725             return result;
726         }
727     };
728 }
729