1 /*
2  * Copyright (C) 2016 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 import static android.content.Intent.EXTRA_USER;
20 import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
21 import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
22 import static android.provider.Settings.ACTION_ADD_ACCOUNT;
23 import static android.provider.Settings.EXTRA_AUTHORITIES;
24 
25 import android.accounts.Account;
26 import android.accounts.AccountManager;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.UserInfo;
34 import android.content.res.Resources;
35 import android.graphics.drawable.Drawable;
36 import android.os.Bundle;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 import android.text.BidiFormatter;
40 import android.util.ArrayMap;
41 import android.util.Log;
42 import android.util.SparseArray;
43 
44 import androidx.annotation.VisibleForTesting;
45 import androidx.preference.Preference;
46 import androidx.preference.Preference.OnPreferenceClickListener;
47 import androidx.preference.PreferenceGroup;
48 import androidx.preference.PreferenceScreen;
49 
50 import com.android.settings.AccessiblePreferenceCategory;
51 import com.android.settings.R;
52 import com.android.settings.SettingsPreferenceFragment;
53 import com.android.settings.Utils;
54 import com.android.settings.core.PreferenceControllerMixin;
55 import com.android.settings.core.SubSettingLauncher;
56 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
57 import com.android.settings.overlay.FeatureFactory;
58 import com.android.settingslib.RestrictedPreference;
59 import com.android.settingslib.accounts.AuthenticatorHelper;
60 import com.android.settingslib.core.AbstractPreferenceController;
61 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
62 import com.android.settingslib.core.lifecycle.LifecycleObserver;
63 import com.android.settingslib.core.lifecycle.events.OnPause;
64 import com.android.settingslib.core.lifecycle.events.OnResume;
65 import com.android.settingslib.search.SearchIndexableRaw;
66 
67 import java.util.ArrayList;
68 import java.util.Collections;
69 import java.util.Comparator;
70 import java.util.List;
71 
72 public class AccountPreferenceController extends AbstractPreferenceController
73         implements PreferenceControllerMixin, AuthenticatorHelper.OnAccountsUpdateListener,
74         OnPreferenceClickListener, LifecycleObserver, OnPause, OnResume {
75 
76     private static final String TAG = "AccountPrefController";
77 
78     private static final int ORDER_ACCOUNT_PROFILES = 101;
79     private static final int ORDER_LAST = 1002;
80     private static final int ORDER_NEXT_TO_LAST = 1001;
81     private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000;
82 
83     private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
84     private static final String PREF_KEY_REMOVE_PROFILE = "remove_profile";
85     private static final String PREF_KEY_WORK_PROFILE_SETTING = "work_profile_setting";
86 
87     private UserManager mUm;
88     private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
89     private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver =
90             new ManagedProfileBroadcastReceiver();
91     private Preference mProfileNotAvailablePreference;
92     private String[] mAuthorities;
93     private int mAuthoritiesCount = 0;
94     private SettingsPreferenceFragment mFragment;
95     private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
96     private AccountRestrictionHelper mHelper;
97     private MetricsFeatureProvider mMetricsFeatureProvider;
98     private @ProfileSelectFragment.ProfileType int mType;
99 
100     /**
101      * Holds data related to the accounts belonging to one profile.
102      */
103     public static class ProfileData {
104         /**
105          * The preference that displays the accounts.
106          */
107         public PreferenceGroup preferenceGroup;
108         /**
109          * The preference that displays the add account button.
110          */
111         public RestrictedPreference addAccountPreference;
112         /**
113          * The preference that displays the button to remove the managed profile
114          */
115         public RestrictedPreference removeWorkProfilePreference;
116         /**
117          * The preference that displays managed profile settings.
118          */
119         public Preference managedProfilePreference;
120         /**
121          * The {@link AuthenticatorHelper} that holds accounts data for this profile.
122          */
123         public AuthenticatorHelper authenticatorHelper;
124         /**
125          * The {@link UserInfo} of the profile.
126          */
127         public UserInfo userInfo;
128         /**
129          * The {@link UserInfo} of the profile.
130          */
131         public boolean pendingRemoval;
132         /**
133          * The map from account key to account preference
134          */
135         public ArrayMap<String, AccountTypePreference> accountPreferences = new ArrayMap<>();
136     }
137 
AccountPreferenceController(Context context, SettingsPreferenceFragment parent, String[] authorities, @ProfileSelectFragment.ProfileType int type)138     public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
139             String[] authorities, @ProfileSelectFragment.ProfileType int type) {
140         this(context, parent, authorities, new AccountRestrictionHelper(context), type);
141     }
142 
143     @VisibleForTesting
AccountPreferenceController(Context context, SettingsPreferenceFragment parent, String[] authorities, AccountRestrictionHelper helper, @ProfileSelectFragment.ProfileType int type)144     AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
145             String[] authorities, AccountRestrictionHelper helper,
146             @ProfileSelectFragment.ProfileType int type) {
147         super(context);
148         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
149         mAuthorities = authorities;
150         mFragment = parent;
151         if (mAuthorities != null) {
152             mAuthoritiesCount = mAuthorities.length;
153         }
154         final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
155         mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
156         mHelper = helper;
157         mType = type;
158     }
159 
160     @Override
isAvailable()161     public boolean isAvailable() {
162         return !mUm.isManagedProfile();
163     }
164 
165     @Override
getPreferenceKey()166     public String getPreferenceKey() {
167         return null;
168     }
169 
170     @Override
displayPreference(PreferenceScreen screen)171     public void displayPreference(PreferenceScreen screen) {
172         super.displayPreference(screen);
173         updateUi();
174     }
175 
176     @Override
updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData)177     public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
178         if (!isAvailable()) {
179             return;
180         }
181         final Resources res = mContext.getResources();
182         final String screenTitle = res.getString(R.string.account_settings_title);
183 
184         List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
185         for (final UserInfo userInfo : profiles) {
186             if (userInfo.isEnabled() && userInfo.isManagedProfile()) {
187                 if (!mHelper.hasBaseUserRestriction(DISALLOW_REMOVE_MANAGED_PROFILE,
188                         UserHandle.myUserId())) {
189                     final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
190                     data.key = PREF_KEY_REMOVE_PROFILE;
191                     data.title = res.getString(R.string.remove_managed_profile_label);
192                     data.screenTitle = screenTitle;
193                     rawData.add(data);
194                 }
195                 final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
196                 data.key = PREF_KEY_WORK_PROFILE_SETTING;
197                 data.title = res.getString(R.string.managed_profile_settings_title);
198                 data.screenTitle = screenTitle;
199                 rawData.add(data);
200             }
201         }
202     }
203 
204     @Override
onResume()205     public void onResume() {
206         updateUi();
207         mManagedProfileBroadcastReceiver.register(mContext);
208         listenToAccountUpdates();
209     }
210 
211     @Override
onPause()212     public void onPause() {
213         stopListeningToAccountUpdates();
214         mManagedProfileBroadcastReceiver.unregister(mContext);
215     }
216 
217     @Override
onAccountsUpdate(UserHandle userHandle)218     public void onAccountsUpdate(UserHandle userHandle) {
219         final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
220         if (profileData != null) {
221             updateAccountTypes(profileData);
222         } else {
223             Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
224         }
225     }
226 
227     @Override
onPreferenceClick(Preference preference)228     public boolean onPreferenceClick(Preference preference) {
229         final int metricsCategory = mFragment.getMetricsCategory();
230         // Check the preference
231         final int count = mProfiles.size();
232         for (int i = 0; i < count; i++) {
233             ProfileData profileData = mProfiles.valueAt(i);
234             if (preference == profileData.addAccountPreference) {
235                 mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
236                 Intent intent = new Intent(ACTION_ADD_ACCOUNT);
237                 intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
238                 intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
239                 mContext.startActivity(intent);
240                 return true;
241             }
242             if (preference == profileData.removeWorkProfilePreference) {
243                 mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
244                 final int userId = profileData.userInfo.id;
245                 RemoveUserFragment.newInstance(userId).show(mFragment.getFragmentManager(),
246                         "removeUser");
247                 return true;
248             }
249             if (preference == profileData.managedProfilePreference) {
250                 mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
251                 Bundle arguments = new Bundle();
252                 arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle());
253                 new SubSettingLauncher(mContext)
254                         .setSourceMetricsCategory(metricsCategory)
255                         .setDestination(ManagedProfileSettings.class.getName())
256                         .setTitleRes(R.string.managed_profile_settings_title)
257                         .setArguments(arguments)
258                         .launch();
259 
260                 return true;
261             }
262         }
263         return false;
264     }
265 
updateUi()266     private void updateUi() {
267         if (!isAvailable()) {
268             // This should not happen
269             Log.e(TAG, "We should not be showing settings for a managed profile");
270             return;
271         }
272 
273         for (int i = 0, size = mProfiles.size(); i < size; i++) {
274             mProfiles.valueAt(i).pendingRemoval = true;
275         }
276         if (mUm.isRestrictedProfile()) {
277             // Restricted user or similar
278             UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
279             updateProfileUi(userInfo);
280         } else {
281             List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
282             final int profilesCount = profiles.size();
283             for (int i = 0; i < profilesCount; i++) {
284                 if (profiles.get(i).isManagedProfile()
285                         && (mType & ProfileSelectFragment.ProfileType.WORK) != 0) {
286                     updateProfileUi(profiles.get(i));
287                 } else if (!profiles.get(i).isManagedProfile()
288                         && (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0) {
289                     updateProfileUi(profiles.get(i));
290                 }
291             }
292         }
293         cleanUpPreferences();
294 
295         // Add all preferences, starting with one for the primary profile.
296         // Note that we're relying on the ordering given by the SparseArray keys, and on the
297         // value of UserHandle.USER_OWNER being smaller than all the rest.
298         final int profilesCount = mProfiles.size();
299         for (int i = 0; i < profilesCount; i++) {
300             updateAccountTypes(mProfiles.valueAt(i));
301         }
302     }
303 
updateProfileUi(final UserInfo userInfo)304     private void updateProfileUi(final UserInfo userInfo) {
305         if (mFragment.getPreferenceManager() == null) {
306             return;
307         }
308         final ProfileData data = mProfiles.get(userInfo.id);
309         if (data != null) {
310             data.pendingRemoval = false;
311             data.userInfo = userInfo;
312             if (userInfo.isEnabled()) {
313                 // recreate the authentication helper to refresh the list of enabled accounts
314                 data.authenticatorHelper =
315                         new AuthenticatorHelper(mContext, userInfo.getUserHandle(), this);
316             }
317             return;
318         }
319         final Context context = mContext;
320         final ProfileData profileData = new ProfileData();
321         profileData.userInfo = userInfo;
322         AccessiblePreferenceCategory preferenceGroup =
323                 mHelper.createAccessiblePreferenceCategory(
324                         mFragment.getPreferenceManager().getContext());
325         preferenceGroup.setOrder(mAccountProfileOrder++);
326         preferenceGroup.setTitle(R.string.account_settings); // default title; may be modified below
327         if (isSingleProfile()) {
328             final String title = context.getString(R.string.account_for_section_header,
329                     BidiFormatter.getInstance().unicodeWrap(userInfo.name));
330             preferenceGroup.setTitle(title);
331             preferenceGroup.setContentDescription(title);
332         } else if (userInfo.isManagedProfile()) {
333             if (mType == ProfileSelectFragment.ProfileType.ALL) {
334                 preferenceGroup.setTitle(R.string.category_work);
335                 final String workGroupSummary = getWorkGroupSummary(context, userInfo);
336                 preferenceGroup.setSummary(workGroupSummary);
337                 preferenceGroup.setContentDescription(
338                         mContext.getString(R.string.accessibility_category_work, workGroupSummary));
339             }
340             profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference();
341             mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
342                     DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
343             profileData.managedProfilePreference = newManagedProfileSettings();
344         } else {
345             if (mType == ProfileSelectFragment.ProfileType.ALL) {
346                 preferenceGroup.setTitle(R.string.category_personal);
347                 preferenceGroup.setContentDescription(
348                         mContext.getString(R.string.accessibility_category_personal));
349             }
350         }
351         final PreferenceScreen screen = mFragment.getPreferenceScreen();
352         if (screen != null) {
353             screen.addPreference(preferenceGroup);
354         }
355         profileData.preferenceGroup = preferenceGroup;
356         if (userInfo.isEnabled()) {
357             profileData.authenticatorHelper = new AuthenticatorHelper(context,
358                     userInfo.getUserHandle(), this);
359             profileData.addAccountPreference = newAddAccountPreference();
360             mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
361                     DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
362         }
363         mProfiles.put(userInfo.id, profileData);
364     }
365 
newAddAccountPreference()366     private RestrictedPreference newAddAccountPreference() {
367         RestrictedPreference preference =
368                 new RestrictedPreference(mFragment.getPreferenceManager().getContext());
369         preference.setKey(PREF_KEY_ADD_ACCOUNT);
370         preference.setTitle(R.string.add_account_label);
371         preference.setIcon(R.drawable.ic_add_24dp);
372         preference.setOnPreferenceClickListener(this);
373         preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
374         return preference;
375     }
376 
newRemoveWorkProfilePreference()377     private RestrictedPreference newRemoveWorkProfilePreference() {
378         RestrictedPreference preference = new RestrictedPreference(
379                 mFragment.getPreferenceManager().getContext());
380         preference.setKey(PREF_KEY_REMOVE_PROFILE);
381         preference.setTitle(R.string.remove_managed_profile_label);
382         preference.setIcon(R.drawable.ic_delete);
383         preference.setOnPreferenceClickListener(this);
384         preference.setOrder(ORDER_LAST);
385         return preference;
386     }
387 
388 
newManagedProfileSettings()389     private Preference newManagedProfileSettings() {
390         Preference preference = new Preference(mFragment.getPreferenceManager().getContext());
391         preference.setKey(PREF_KEY_WORK_PROFILE_SETTING);
392         preference.setTitle(R.string.managed_profile_settings_title);
393         preference.setIcon(R.drawable.ic_settings_24dp);
394         preference.setOnPreferenceClickListener(this);
395         preference.setOrder(ORDER_NEXT_TO_LAST);
396         return preference;
397     }
398 
getWorkGroupSummary(Context context, UserInfo userInfo)399     private String getWorkGroupSummary(Context context, UserInfo userInfo) {
400         PackageManager packageManager = context.getPackageManager();
401         ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
402         if (adminApplicationInfo == null) {
403             return null;
404         }
405         CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
406         return mContext.getString(R.string.managing_admin, appLabel);
407     }
408 
cleanUpPreferences()409     void cleanUpPreferences() {
410         PreferenceScreen screen = mFragment.getPreferenceScreen();
411         if (screen == null) {
412             return;
413         }
414         final int count = mProfiles.size();
415         for (int i = count - 1; i >= 0; i--) {
416             final ProfileData data = mProfiles.valueAt(i);
417             if (data.pendingRemoval) {
418                 screen.removePreference(data.preferenceGroup);
419                 mProfiles.removeAt(i);
420             }
421         }
422     }
423 
listenToAccountUpdates()424     private void listenToAccountUpdates() {
425         final int count = mProfiles.size();
426         for (int i = 0; i < count; i++) {
427             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
428             if (authenticatorHelper != null) {
429                 authenticatorHelper.listenToAccountUpdates();
430             }
431         }
432     }
433 
stopListeningToAccountUpdates()434     private void stopListeningToAccountUpdates() {
435         final int count = mProfiles.size();
436         for (int i = 0; i < count; i++) {
437             AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
438             if (authenticatorHelper != null) {
439                 authenticatorHelper.stopListeningToAccountUpdates();
440             }
441         }
442     }
443 
updateAccountTypes(ProfileData profileData)444     private void updateAccountTypes(ProfileData profileData) {
445         if (mFragment.getPreferenceManager() == null
446                 || profileData.preferenceGroup.getPreferenceManager() == null) {
447             // This could happen if activity is finishing
448             return;
449         }
450         if (profileData.userInfo.isEnabled()) {
451             final ArrayMap<String, AccountTypePreference> preferenceToRemove =
452                     new ArrayMap<>(profileData.accountPreferences);
453             final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
454                     profileData.authenticatorHelper, profileData.userInfo.getUserHandle(),
455                     preferenceToRemove);
456             final int count = preferences.size();
457             for (int i = 0; i < count; i++) {
458                 final AccountTypePreference preference = preferences.get(i);
459                 preference.setOrder(i);
460                 final String key = preference.getKey();
461                 if (!profileData.accountPreferences.containsKey(key)) {
462                     profileData.preferenceGroup.addPreference(preference);
463                     profileData.accountPreferences.put(key, preference);
464                 }
465             }
466             if (profileData.addAccountPreference != null) {
467                 profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
468             }
469             for (String key : preferenceToRemove.keySet()) {
470                 profileData.preferenceGroup.removePreference(
471                         profileData.accountPreferences.get(key));
472                 profileData.accountPreferences.remove(key);
473             }
474         } else {
475             profileData.preferenceGroup.removeAll();
476             // Put a label instead of the accounts list
477             if (mProfileNotAvailablePreference == null) {
478                 mProfileNotAvailablePreference =
479                         new Preference(mFragment.getPreferenceManager().getContext());
480             }
481             mProfileNotAvailablePreference.setEnabled(false);
482             mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
483             mProfileNotAvailablePreference.setTitle(null);
484             mProfileNotAvailablePreference.setSummary(
485                     R.string.managed_profile_not_available_label);
486             profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
487         }
488         if (profileData.removeWorkProfilePreference != null) {
489             profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
490         }
491         if (profileData.managedProfilePreference != null) {
492             profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
493         }
494     }
495 
getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle, ArrayMap<String, AccountTypePreference> preferenceToRemove)496     private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
497             UserHandle userHandle, ArrayMap<String, AccountTypePreference> preferenceToRemove) {
498         final String[] accountTypes = helper.getEnabledAccountTypes();
499         final ArrayList<AccountTypePreference> accountTypePreferences =
500                 new ArrayList<>(accountTypes.length);
501 
502         for (int i = 0; i < accountTypes.length; i++) {
503             final String accountType = accountTypes[i];
504             // Skip showing any account that does not have any of the requested authorities
505             if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
506                 continue;
507             }
508             final CharSequence label = helper.getLabelForType(mContext, accountType);
509             if (label == null) {
510                 continue;
511             }
512             final String titleResPackageName = helper.getPackageForType(accountType);
513             final int titleResId = helper.getLabelIdForType(accountType);
514 
515             final Account[] accounts = AccountManager.get(mContext)
516                     .getAccountsByTypeAsUser(accountType, userHandle);
517             final Drawable icon = helper.getDrawableForType(mContext, accountType);
518             final Context prefContext = mFragment.getPreferenceManager().getContext();
519 
520             // Add a preference row for each individual account
521             for (Account account : accounts) {
522                 final AccountTypePreference preference =
523                         preferenceToRemove.remove(AccountTypePreference.buildKey(account));
524                 if (preference != null) {
525                     accountTypePreferences.add(preference);
526                     continue;
527                 }
528                 final ArrayList<String> auths =
529                         helper.getAuthoritiesForAccountType(account.type);
530                 if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
531                     continue;
532                 }
533                 final Bundle fragmentArguments = new Bundle();
534                 fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
535                         account);
536                 fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
537                         userHandle);
538                 fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
539                         accountType);
540                 fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
541                         label.toString());
542                 fragmentArguments.putInt(AccountDetailDashboardFragment.KEY_ACCOUNT_TITLE_RES,
543                         titleResId);
544                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
545                 accountTypePreferences.add(new AccountTypePreference(
546                         prefContext, mMetricsFeatureProvider.getMetricsCategory(mFragment),
547                         account, titleResPackageName, titleResId, label,
548                         AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
549             }
550             helper.preloadDrawableForType(mContext, accountType);
551         }
552         // Sort by label
553         Collections.sort(accountTypePreferences, new Comparator<AccountTypePreference>() {
554             @Override
555             public int compare(AccountTypePreference t1, AccountTypePreference t2) {
556                 int result = t1.getSummary().toString().compareTo(t2.getSummary().toString());
557                 return result != 0
558                         ? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
559             }
560         });
561         return accountTypePreferences;
562     }
563 
accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)564     private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
565             String accountType) {
566         if (mAuthoritiesCount == 0) {
567             // No authorities required
568             return true;
569         }
570         final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
571                 accountType);
572         if (authoritiesForType == null) {
573             Log.d(TAG, "No sync authorities for account type: " + accountType);
574             return false;
575         }
576         for (int j = 0; j < mAuthoritiesCount; j++) {
577             if (authoritiesForType.contains(mAuthorities[j])) {
578                 return true;
579             }
580         }
581         return false;
582     }
583 
isSingleProfile()584     private boolean isSingleProfile() {
585         return mUm.isLinkedUser() || mUm.getProfiles(UserHandle.myUserId()).size() == 1;
586     }
587 
588     private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
589         private boolean mListeningToManagedProfileEvents;
590 
591         @Override
onReceive(Context context, Intent intent)592         public void onReceive(Context context, Intent intent) {
593             final String action = intent.getAction();
594             Log.v(TAG, "Received broadcast: " + action);
595             if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
596                     || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
597                 if (mFragment instanceof AccountWorkProfileDashboardFragment) {
598                     mFragment.getActivity().finish();
599                 } else {
600                     // Clean old state
601                     stopListeningToAccountUpdates();
602                     // Build new state
603                     updateUi();
604                     listenToAccountUpdates();
605                 }
606                 return;
607             }
608             Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
609         }
610 
register(Context context)611         public void register(Context context) {
612             if (!mListeningToManagedProfileEvents) {
613                 IntentFilter intentFilter = new IntentFilter();
614                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
615                 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
616                 context.registerReceiver(this, intentFilter);
617                 mListeningToManagedProfileEvents = true;
618             }
619         }
620 
unregister(Context context)621         public void unregister(Context context) {
622             if (mListeningToManagedProfileEvents) {
623                 context.unregisterReceiver(this);
624                 mListeningToManagedProfileEvents = false;
625             }
626         }
627     }
628 }
629