This change renames clone profile accounts header on the account management dashboard to "Clone" from "Personal" by using the newly added clone category header config. This also includes changes to remove the add account preference from the clone profile accounts. Bug: 260181765 Test: Flashed on a sunfish device and tested Change-Id: Iff8b75119d85d2cd8ab065ed1057fb2b35e64650
693 lines
31 KiB
Java
693 lines
31 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.accounts;
|
|
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_CLONE;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.CLONE_CATEGORY_HEADER;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_BY;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_PROFILE_SETTINGS_TITLE;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_WORK_PROFILE;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
|
|
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOT_AVAILABLE;
|
|
import static android.content.Intent.EXTRA_USER;
|
|
import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
|
import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
|
|
import static android.provider.Settings.ACTION_ADD_ACCOUNT;
|
|
import static android.provider.Settings.EXTRA_AUTHORITIES;
|
|
|
|
import android.accounts.Account;
|
|
import android.accounts.AccountManager;
|
|
import android.app.admin.DevicePolicyManager;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.UserInfo;
|
|
import android.content.res.Resources;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Bundle;
|
|
import android.os.UserHandle;
|
|
import android.os.UserManager;
|
|
import android.text.BidiFormatter;
|
|
import android.util.ArrayMap;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.preference.Preference;
|
|
import androidx.preference.Preference.OnPreferenceClickListener;
|
|
import androidx.preference.PreferenceGroup;
|
|
import androidx.preference.PreferenceScreen;
|
|
|
|
import com.android.settings.AccessiblePreferenceCategory;
|
|
import com.android.settings.R;
|
|
import com.android.settings.Utils;
|
|
import com.android.settings.core.PreferenceControllerMixin;
|
|
import com.android.settings.core.SubSettingLauncher;
|
|
import com.android.settings.dashboard.DashboardFragment;
|
|
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
|
|
import com.android.settings.overlay.FeatureFactory;
|
|
import com.android.settingslib.RestrictedPreference;
|
|
import com.android.settingslib.accounts.AuthenticatorHelper;
|
|
import com.android.settingslib.core.AbstractPreferenceController;
|
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
|
import com.android.settingslib.core.lifecycle.events.OnPause;
|
|
import com.android.settingslib.core.lifecycle.events.OnResume;
|
|
import com.android.settingslib.search.SearchIndexableRaw;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
|
|
public class AccountPreferenceController extends AbstractPreferenceController
|
|
implements PreferenceControllerMixin, AuthenticatorHelper.OnAccountsUpdateListener,
|
|
OnPreferenceClickListener, LifecycleObserver, OnPause, OnResume {
|
|
|
|
private static final String TAG = "AccountPrefController";
|
|
|
|
private static final int ORDER_ACCOUNT_PROFILES = 101;
|
|
private static final int ORDER_LAST = 1002;
|
|
private static final int ORDER_NEXT_TO_LAST = 1001;
|
|
private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000;
|
|
|
|
private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
|
|
private static final String PREF_KEY_REMOVE_PROFILE = "remove_profile";
|
|
private static final String PREF_KEY_WORK_PROFILE_SETTING = "work_profile_setting";
|
|
|
|
private UserManager mUm;
|
|
private DevicePolicyManager mDpm;
|
|
private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
|
|
private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver =
|
|
new ManagedProfileBroadcastReceiver();
|
|
private Preference mProfileNotAvailablePreference;
|
|
private String[] mAuthorities;
|
|
private int mAuthoritiesCount = 0;
|
|
private DashboardFragment mFragment;
|
|
private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
|
|
private AccountRestrictionHelper mHelper;
|
|
private MetricsFeatureProvider mMetricsFeatureProvider;
|
|
private @ProfileSelectFragment.ProfileType int mType;
|
|
|
|
/**
|
|
* Holds data related to the accounts belonging to one profile.
|
|
*/
|
|
public static class ProfileData {
|
|
/**
|
|
* The preference that displays the accounts.
|
|
*/
|
|
public PreferenceGroup preferenceGroup;
|
|
/**
|
|
* The preference that displays the add account button.
|
|
*/
|
|
public RestrictedPreference addAccountPreference;
|
|
/**
|
|
* The preference that displays the button to remove the managed profile
|
|
*/
|
|
public RestrictedPreference removeWorkProfilePreference;
|
|
/**
|
|
* The preference that displays managed profile settings.
|
|
*/
|
|
public Preference managedProfilePreference;
|
|
/**
|
|
* The {@link AuthenticatorHelper} that holds accounts data for this profile.
|
|
*/
|
|
public AuthenticatorHelper authenticatorHelper;
|
|
/**
|
|
* The {@link UserInfo} of the profile.
|
|
*/
|
|
public UserInfo userInfo;
|
|
/**
|
|
* The {@link UserInfo} of the profile.
|
|
*/
|
|
public boolean pendingRemoval;
|
|
/**
|
|
* The map from account key to account preference
|
|
*/
|
|
public ArrayMap<String, AccountTypePreference> accountPreferences = new ArrayMap<>();
|
|
}
|
|
|
|
public AccountPreferenceController(Context context, DashboardFragment parent,
|
|
String[] authorities, @ProfileSelectFragment.ProfileType int type) {
|
|
this(context, parent, authorities, new AccountRestrictionHelper(context), type);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
AccountPreferenceController(Context context, DashboardFragment parent,
|
|
String[] authorities, AccountRestrictionHelper helper,
|
|
@ProfileSelectFragment.ProfileType int type) {
|
|
super(context);
|
|
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
|
mDpm = context.getSystemService(DevicePolicyManager.class);
|
|
mAuthorities = authorities;
|
|
mFragment = parent;
|
|
if (mAuthorities != null) {
|
|
mAuthoritiesCount = mAuthorities.length;
|
|
}
|
|
final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
|
|
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
|
|
mHelper = helper;
|
|
mType = type;
|
|
}
|
|
|
|
@Override
|
|
public boolean isAvailable() {
|
|
return !mUm.isManagedProfile();
|
|
}
|
|
|
|
@Override
|
|
public String getPreferenceKey() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void displayPreference(PreferenceScreen screen) {
|
|
super.displayPreference(screen);
|
|
updateUi();
|
|
}
|
|
|
|
@Override
|
|
public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
|
if (!isAvailable()) {
|
|
return;
|
|
}
|
|
final Resources res = mContext.getResources();
|
|
final String screenTitle = res.getString(R.string.account_settings_title);
|
|
|
|
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
|
|
for (final UserInfo userInfo : profiles) {
|
|
if (userInfo.isEnabled() && userInfo.isManagedProfile()) {
|
|
if (!mHelper.hasBaseUserRestriction(DISALLOW_REMOVE_MANAGED_PROFILE,
|
|
UserHandle.myUserId())) {
|
|
final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
|
data.key = PREF_KEY_REMOVE_PROFILE;
|
|
data.title = mDpm.getResources().getString(
|
|
REMOVE_WORK_PROFILE,
|
|
() -> res.getString(R.string.remove_managed_profile_label));
|
|
data.screenTitle = screenTitle;
|
|
rawData.add(data);
|
|
}
|
|
final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
|
data.key = PREF_KEY_WORK_PROFILE_SETTING;
|
|
data.title = mDpm.getResources().getString(MANAGED_PROFILE_SETTINGS_TITLE,
|
|
() -> res.getString(R.string.managed_profile_settings_title));
|
|
data.screenTitle = screenTitle;
|
|
rawData.add(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
updateUi();
|
|
mManagedProfileBroadcastReceiver.register(mContext);
|
|
listenToAccountUpdates();
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
stopListeningToAccountUpdates();
|
|
mManagedProfileBroadcastReceiver.unregister(mContext);
|
|
}
|
|
|
|
@Override
|
|
public void onAccountsUpdate(UserHandle userHandle) {
|
|
final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
|
|
if (profileData != null) {
|
|
updateAccountTypes(profileData);
|
|
} else {
|
|
Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
final int metricsCategory = mFragment.getMetricsCategory();
|
|
// Check the preference
|
|
final int count = mProfiles.size();
|
|
for (int i = 0; i < count; i++) {
|
|
ProfileData profileData = mProfiles.valueAt(i);
|
|
if (preference == profileData.addAccountPreference) {
|
|
mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
|
|
Intent intent = new Intent(ACTION_ADD_ACCOUNT);
|
|
intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
|
|
intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
|
|
mContext.startActivity(intent);
|
|
return true;
|
|
}
|
|
if (preference == profileData.removeWorkProfilePreference) {
|
|
mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
|
|
final int userId = profileData.userInfo.id;
|
|
RemoveUserFragment.newInstance(userId).show(mFragment.getFragmentManager(),
|
|
"removeUser");
|
|
return true;
|
|
}
|
|
if (preference == profileData.managedProfilePreference) {
|
|
mMetricsFeatureProvider.logClickedPreference(preference, metricsCategory);
|
|
Bundle arguments = new Bundle();
|
|
arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle());
|
|
new SubSettingLauncher(mContext)
|
|
.setSourceMetricsCategory(metricsCategory)
|
|
.setDestination(ManagedProfileSettings.class.getName())
|
|
.setTitleText(mDpm.getResources().getString(MANAGED_PROFILE_SETTINGS_TITLE,
|
|
() -> mContext.getString(R.string.managed_profile_settings_title)))
|
|
.setArguments(arguments)
|
|
.launch();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void updateUi() {
|
|
if (!isAvailable()) {
|
|
// This should not happen
|
|
Log.e(TAG, "We should not be showing settings for a managed profile");
|
|
return;
|
|
}
|
|
|
|
for (int i = 0, size = mProfiles.size(); i < size; i++) {
|
|
mProfiles.valueAt(i).pendingRemoval = true;
|
|
}
|
|
if (mUm.isRestrictedProfile()) {
|
|
// Restricted user or similar
|
|
UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
|
|
updateProfileUi(userInfo);
|
|
} else {
|
|
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
|
|
final int profilesCount = profiles.size();
|
|
for (int i = 0; i < profilesCount; i++) {
|
|
if (profiles.get(i).isManagedProfile()
|
|
&& (mType & ProfileSelectFragment.ProfileType.WORK) != 0) {
|
|
updateProfileUi(profiles.get(i));
|
|
} else if (!profiles.get(i).isManagedProfile()
|
|
&& (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0) {
|
|
updateProfileUi(profiles.get(i));
|
|
}
|
|
}
|
|
}
|
|
cleanUpPreferences();
|
|
|
|
// Add all preferences, starting with one for the primary profile.
|
|
// Note that we're relying on the ordering given by the SparseArray keys, and on the
|
|
// value of UserHandle.USER_OWNER being smaller than all the rest.
|
|
final int profilesCount = mProfiles.size();
|
|
for (int i = 0; i < profilesCount; i++) {
|
|
updateAccountTypes(mProfiles.valueAt(i));
|
|
}
|
|
|
|
// Refresh for the auto-sync preferences
|
|
mFragment.forceUpdatePreferences();
|
|
}
|
|
|
|
private void updateProfileUi(final UserInfo userInfo) {
|
|
if (mFragment.getPreferenceManager() == null) {
|
|
return;
|
|
}
|
|
final ProfileData data = mProfiles.get(userInfo.id);
|
|
if (data != null) {
|
|
data.pendingRemoval = false;
|
|
data.userInfo = userInfo;
|
|
if (userInfo.isEnabled()) {
|
|
// recreate the authentication helper to refresh the list of enabled accounts
|
|
data.authenticatorHelper =
|
|
new AuthenticatorHelper(mContext, userInfo.getUserHandle(), this);
|
|
}
|
|
return;
|
|
}
|
|
final Context context = mContext;
|
|
final ProfileData profileData = new ProfileData();
|
|
profileData.userInfo = userInfo;
|
|
AccessiblePreferenceCategory preferenceGroup =
|
|
mHelper.createAccessiblePreferenceCategory(
|
|
mFragment.getPreferenceManager().getContext());
|
|
preferenceGroup.setOrder(mAccountProfileOrder++);
|
|
preferenceGroup.setTitle(R.string.account_settings); // default title; may be modified below
|
|
if (isSingleProfile()) {
|
|
final String title = context.getString(R.string.account_for_section_header,
|
|
BidiFormatter.getInstance().unicodeWrap(userInfo.name));
|
|
preferenceGroup.setTitle(title);
|
|
preferenceGroup.setContentDescription(title);
|
|
} else if (userInfo.isManagedProfile()) {
|
|
if (mType == ProfileSelectFragment.ProfileType.ALL) {
|
|
setCategoryTitleFromDevicePolicyResource(preferenceGroup, WORK_CATEGORY_HEADER,
|
|
R.string.category_work);
|
|
final String workGroupSummary = getWorkGroupSummary(context, userInfo);
|
|
preferenceGroup.setSummary(workGroupSummary);
|
|
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
|
|
ACCESSIBILITY_CATEGORY_WORK, R.string.accessibility_category_work,
|
|
workGroupSummary);
|
|
}
|
|
profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference();
|
|
mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
|
|
DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
|
|
profileData.managedProfilePreference = newManagedProfileSettings();
|
|
} else if (userInfo.isCloneProfile()) {
|
|
if (mType == ProfileSelectFragment.ProfileType.ALL) {
|
|
setCategoryTitleFromDevicePolicyResource(preferenceGroup, CLONE_CATEGORY_HEADER,
|
|
R.string.category_clone);
|
|
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
|
|
ACCESSIBILITY_CATEGORY_CLONE, R.string.accessibility_category_clone,
|
|
null);
|
|
}
|
|
} else {
|
|
// Primary Profile
|
|
if (mType == ProfileSelectFragment.ProfileType.ALL) {
|
|
setCategoryTitleFromDevicePolicyResource(preferenceGroup, PERSONAL_CATEGORY_HEADER,
|
|
R.string.category_personal);
|
|
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
|
|
ACCESSIBILITY_CATEGORY_PERSONAL, R.string.accessibility_category_personal,
|
|
null);
|
|
}
|
|
}
|
|
final PreferenceScreen screen = mFragment.getPreferenceScreen();
|
|
if (screen != null) {
|
|
screen.addPreference(preferenceGroup);
|
|
}
|
|
profileData.preferenceGroup = preferenceGroup;
|
|
if (userInfo.isEnabled()) {
|
|
profileData.authenticatorHelper = new AuthenticatorHelper(context,
|
|
userInfo.getUserHandle(), this);
|
|
if (!userInfo.isCloneProfile()) {
|
|
profileData.addAccountPreference = newAddAccountPreference();
|
|
mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
|
|
DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
|
|
}
|
|
}
|
|
mProfiles.put(userInfo.id, profileData);
|
|
}
|
|
|
|
private void setCategoryTitleFromDevicePolicyResource(
|
|
AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier) {
|
|
preferenceGroup.setTitle(
|
|
mDpm.getResources().getString(stringId,
|
|
() -> mContext.getString(resourceIdentifier)));
|
|
}
|
|
|
|
private void setContentDescriptionFromDevicePolicyResource(
|
|
AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier,
|
|
String formatArgs) {
|
|
preferenceGroup.setContentDescription(mDpm.getResources().getString(stringId, () -> {
|
|
if (formatArgs != null) {
|
|
return mContext.getString(resourceIdentifier, formatArgs);
|
|
}
|
|
return mContext.getString(resourceIdentifier);
|
|
}));
|
|
}
|
|
|
|
private RestrictedPreference newAddAccountPreference() {
|
|
RestrictedPreference preference =
|
|
new RestrictedPreference(mFragment.getPreferenceManager().getContext());
|
|
preference.setKey(PREF_KEY_ADD_ACCOUNT);
|
|
preference.setTitle(R.string.add_account_label);
|
|
preference.setIcon(R.drawable.ic_add_24dp);
|
|
preference.setOnPreferenceClickListener(this);
|
|
preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
|
|
return preference;
|
|
}
|
|
|
|
private RestrictedPreference newRemoveWorkProfilePreference() {
|
|
RestrictedPreference preference = new RestrictedPreference(
|
|
mFragment.getPreferenceManager().getContext());
|
|
preference.setKey(PREF_KEY_REMOVE_PROFILE);
|
|
preference.setTitle(
|
|
mDpm.getResources().getString(REMOVE_WORK_PROFILE,
|
|
() -> mContext.getString(R.string.remove_managed_profile_label)));
|
|
preference.setIcon(R.drawable.ic_delete);
|
|
preference.setOnPreferenceClickListener(this);
|
|
preference.setOrder(ORDER_LAST);
|
|
return preference;
|
|
}
|
|
|
|
private Preference newManagedProfileSettings() {
|
|
Preference preference = new Preference(mFragment.getPreferenceManager().getContext());
|
|
preference.setKey(PREF_KEY_WORK_PROFILE_SETTING);
|
|
preference.setTitle(mDpm.getResources().getString(MANAGED_PROFILE_SETTINGS_TITLE,
|
|
() -> mContext.getString(R.string.managed_profile_settings_title)));
|
|
preference.setIcon(R.drawable.ic_settings_24dp);
|
|
preference.setOnPreferenceClickListener(this);
|
|
preference.setOrder(ORDER_NEXT_TO_LAST);
|
|
return preference;
|
|
}
|
|
|
|
private String getWorkGroupSummary(Context context, UserInfo userInfo) {
|
|
PackageManager packageManager = context.getPackageManager();
|
|
ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
|
|
if (adminApplicationInfo == null) {
|
|
return null;
|
|
}
|
|
CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
|
|
return mDpm.getResources().getString(MANAGED_BY,
|
|
() -> mContext.getString(R.string.managing_admin, appLabel), appLabel);
|
|
}
|
|
|
|
void cleanUpPreferences() {
|
|
PreferenceScreen screen = mFragment.getPreferenceScreen();
|
|
if (screen == null) {
|
|
return;
|
|
}
|
|
final int count = mProfiles.size();
|
|
for (int i = count - 1; i >= 0; i--) {
|
|
final ProfileData data = mProfiles.valueAt(i);
|
|
if (data.pendingRemoval) {
|
|
screen.removePreference(data.preferenceGroup);
|
|
mProfiles.removeAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void listenToAccountUpdates() {
|
|
final int count = mProfiles.size();
|
|
for (int i = 0; i < count; i++) {
|
|
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
|
if (authenticatorHelper != null) {
|
|
authenticatorHelper.listenToAccountUpdates();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void stopListeningToAccountUpdates() {
|
|
final int count = mProfiles.size();
|
|
for (int i = 0; i < count; i++) {
|
|
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
|
if (authenticatorHelper != null) {
|
|
authenticatorHelper.stopListeningToAccountUpdates();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateAccountTypes(ProfileData profileData) {
|
|
if (mFragment.getPreferenceManager() == null
|
|
|| profileData.preferenceGroup.getPreferenceManager() == null) {
|
|
// This could happen if activity is finishing
|
|
return;
|
|
}
|
|
if (profileData.userInfo.isEnabled()) {
|
|
final ArrayMap<String, AccountTypePreference> preferenceToRemove =
|
|
new ArrayMap<>(profileData.accountPreferences);
|
|
final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
|
|
profileData.authenticatorHelper, profileData.userInfo.getUserHandle(),
|
|
preferenceToRemove);
|
|
final int count = preferences.size();
|
|
for (int i = 0; i < count; i++) {
|
|
final AccountTypePreference preference = preferences.get(i);
|
|
preference.setOrder(i);
|
|
final String key = preference.getKey();
|
|
if (!profileData.accountPreferences.containsKey(key)) {
|
|
profileData.preferenceGroup.addPreference(preference);
|
|
profileData.accountPreferences.put(key, preference);
|
|
}
|
|
}
|
|
if (profileData.addAccountPreference != null) {
|
|
profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
|
|
}
|
|
for (String key : preferenceToRemove.keySet()) {
|
|
profileData.preferenceGroup.removePreference(
|
|
profileData.accountPreferences.get(key));
|
|
profileData.accountPreferences.remove(key);
|
|
}
|
|
} else {
|
|
profileData.preferenceGroup.removeAll();
|
|
// Put a label instead of the accounts list
|
|
if (mProfileNotAvailablePreference == null) {
|
|
mProfileNotAvailablePreference =
|
|
new Preference(mFragment.getPreferenceManager().getContext());
|
|
}
|
|
mProfileNotAvailablePreference.setEnabled(false);
|
|
mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
|
|
mProfileNotAvailablePreference.setTitle(null);
|
|
mProfileNotAvailablePreference.setSummary(
|
|
mDpm.getResources().getString(
|
|
WORK_PROFILE_NOT_AVAILABLE, () -> mContext.getString(
|
|
R.string.managed_profile_not_available_label)));
|
|
profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
|
|
}
|
|
if (profileData.removeWorkProfilePreference != null) {
|
|
profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
|
|
}
|
|
if (profileData.managedProfilePreference != null) {
|
|
profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
|
|
}
|
|
}
|
|
|
|
private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
|
|
UserHandle userHandle, ArrayMap<String, AccountTypePreference> preferenceToRemove) {
|
|
final String[] accountTypes = helper.getEnabledAccountTypes();
|
|
final ArrayList<AccountTypePreference> accountTypePreferences =
|
|
new ArrayList<>(accountTypes.length);
|
|
|
|
for (int i = 0; i < accountTypes.length; i++) {
|
|
final String accountType = accountTypes[i];
|
|
// Skip showing any account that does not have any of the requested authorities
|
|
if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
|
|
continue;
|
|
}
|
|
final CharSequence label = helper.getLabelForType(mContext, accountType);
|
|
if (label == null) {
|
|
continue;
|
|
}
|
|
final String titleResPackageName = helper.getPackageForType(accountType);
|
|
final int titleResId = helper.getLabelIdForType(accountType);
|
|
|
|
final Account[] accounts = AccountManager.get(mContext)
|
|
.getAccountsByTypeAsUser(accountType, userHandle);
|
|
final Drawable icon = helper.getDrawableForType(mContext, accountType);
|
|
final Context prefContext = mFragment.getPreferenceManager().getContext();
|
|
|
|
// Add a preference row for each individual account
|
|
for (Account account : accounts) {
|
|
final AccountTypePreference preference =
|
|
preferenceToRemove.remove(AccountTypePreference.buildKey(account));
|
|
if (preference != null) {
|
|
accountTypePreferences.add(preference);
|
|
continue;
|
|
}
|
|
final ArrayList<String> auths =
|
|
helper.getAuthoritiesForAccountType(account.type);
|
|
if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
|
|
continue;
|
|
}
|
|
final Bundle fragmentArguments = new Bundle();
|
|
fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
|
|
account);
|
|
fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
|
|
userHandle);
|
|
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
|
|
accountType);
|
|
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
|
|
label.toString());
|
|
fragmentArguments.putInt(AccountDetailDashboardFragment.KEY_ACCOUNT_TITLE_RES,
|
|
titleResId);
|
|
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
|
|
accountTypePreferences.add(new AccountTypePreference(
|
|
prefContext, mMetricsFeatureProvider.getMetricsCategory(mFragment),
|
|
account, titleResPackageName, titleResId, label,
|
|
AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
|
|
}
|
|
helper.preloadDrawableForType(mContext, accountType);
|
|
}
|
|
// Sort by label
|
|
Collections.sort(accountTypePreferences, new Comparator<AccountTypePreference>() {
|
|
@Override
|
|
public int compare(AccountTypePreference t1, AccountTypePreference t2) {
|
|
int result = t1.getSummary().toString().compareTo(t2.getSummary().toString());
|
|
return result != 0
|
|
? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
|
|
}
|
|
});
|
|
return accountTypePreferences;
|
|
}
|
|
|
|
private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
|
|
String accountType) {
|
|
if (mAuthoritiesCount == 0) {
|
|
// No authorities required
|
|
return true;
|
|
}
|
|
final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
|
|
accountType);
|
|
if (authoritiesForType == null) {
|
|
Log.d(TAG, "No sync authorities for account type: " + accountType);
|
|
return false;
|
|
}
|
|
for (int j = 0; j < mAuthoritiesCount; j++) {
|
|
if (authoritiesForType.contains(mAuthorities[j])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean isSingleProfile() {
|
|
return mUm.isLinkedUser() || mUm.getProfiles(UserHandle.myUserId()).size() == 1;
|
|
}
|
|
|
|
private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
|
|
private boolean mListeningToManagedProfileEvents;
|
|
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
final String action = intent.getAction();
|
|
Log.v(TAG, "Received broadcast: " + action);
|
|
if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
|
|
|| action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
|
|
if (mFragment instanceof AccountWorkProfileDashboardFragment) {
|
|
new SubSettingLauncher(context)
|
|
.setDestination(AccountDashboardFragment.class.getName())
|
|
.setSourceMetricsCategory(mFragment.getMetricsCategory())
|
|
.setTitleRes(-1)
|
|
.setIsSecondLayerPage(true)
|
|
.launch();
|
|
mFragment.getActivity().finish();
|
|
} else {
|
|
// Clean old state
|
|
stopListeningToAccountUpdates();
|
|
// Build new state
|
|
updateUi();
|
|
listenToAccountUpdates();
|
|
}
|
|
return;
|
|
}
|
|
Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
|
|
}
|
|
|
|
public void register(Context context) {
|
|
if (!mListeningToManagedProfileEvents) {
|
|
IntentFilter intentFilter = new IntentFilter();
|
|
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
|
|
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
|
|
context.registerReceiver(this, intentFilter);
|
|
mListeningToManagedProfileEvents = true;
|
|
}
|
|
}
|
|
|
|
public void unregister(Context context) {
|
|
if (mListeningToManagedProfileEvents) {
|
|
context.unregisterReceiver(this);
|
|
mListeningToManagedProfileEvents = false;
|
|
}
|
|
}
|
|
}
|
|
}
|