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