Implement policy transparency for CredMan
This CL implements policy transparency for Credential Manager settings. Screenshots: https://hsv.googleplex.com/5502938857340928 https://hsv.googleplex.com/4999933426925568 Test: on device w/ test dpc Bug: 318552220 Change-Id: I78e1fa47541c81e6e2d2bf2c13159be01928e77c
This commit is contained in:
@@ -33,6 +33,9 @@ import android.util.Log;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -236,6 +239,31 @@ public final class CombinedProviderInfo {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether this entry contains a system provider. */
|
||||||
|
public boolean isCredentialManagerSystemProvider() {
|
||||||
|
for (CredentialProviderInfo cpi : mCredentialProviderInfos) {
|
||||||
|
if (cpi.isSystemProvider()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether this entry has device admin restrictions. */
|
||||||
|
@Nullable
|
||||||
|
public RestrictedLockUtils.EnforcedAdmin getDeviceAdminRestrictions(
|
||||||
|
Context context, int userId) {
|
||||||
|
final String packageName = getPackageName();
|
||||||
|
if (TextUtils.isEmpty(packageName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RestrictedLockUtilsInternal.checkIfApplicationCanBeCredentialManagerProvider(
|
||||||
|
context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0),
|
||||||
|
packageName);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the provider that gets the top spot. */
|
/** Returns the provider that gets the top spot. */
|
||||||
public static @Nullable CombinedProviderInfo getTopProvider(
|
public static @Nullable CombinedProviderInfo getTopProvider(
|
||||||
List<CombinedProviderInfo> providers) {
|
List<CombinedProviderInfo> providers) {
|
||||||
@@ -327,8 +355,7 @@ public final class CombinedProviderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable Intent createSettingsActivityIntent(
|
public static @Nullable Intent createSettingsActivityIntent(
|
||||||
@Nullable CharSequence packageName,
|
@Nullable CharSequence packageName, @Nullable CharSequence settingsActivity) {
|
||||||
@Nullable CharSequence settingsActivity) {
|
|
||||||
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(settingsActivity)) {
|
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(settingsActivity)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -69,8 +69,9 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedPreference;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.widget.TwoTargetPreference;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -328,7 +329,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
|
|
||||||
setAvailableServices(
|
setAvailableServices(
|
||||||
mCredentialManager.getCredentialProviderServices(
|
mCredentialManager.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
|
getUser(),
|
||||||
|
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +357,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
// Get the list of new providers and components.
|
// Get the list of new providers and components.
|
||||||
List<CredentialProviderInfo> newProviders =
|
List<CredentialProviderInfo> newProviders =
|
||||||
mCredentialManager.getCredentialProviderServices(
|
mCredentialManager.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
|
getUser(),
|
||||||
|
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN);
|
||||||
Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
|
Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
|
||||||
Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);
|
Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);
|
||||||
|
|
||||||
@@ -548,7 +551,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
icon,
|
icon,
|
||||||
packageName,
|
packageName,
|
||||||
combinedInfo.getSettingsSubtitle(),
|
combinedInfo.getSettingsSubtitle(),
|
||||||
combinedInfo.getSettingsActivity());
|
combinedInfo.getSettingsActivity(),
|
||||||
|
combinedInfo.getDeviceAdminRestrictions(context, getUser()));
|
||||||
output.put(packageName, pref);
|
output.put(packageName, pref);
|
||||||
group.addPreference(pref);
|
group.addPreference(pref);
|
||||||
}
|
}
|
||||||
@@ -569,7 +573,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
service.getServiceIcon(mContext),
|
service.getServiceIcon(mContext),
|
||||||
service.getServiceInfo().packageName,
|
service.getServiceInfo().packageName,
|
||||||
service.getSettingsSubtitle(),
|
service.getSettingsSubtitle(),
|
||||||
service.getSettingsActivity());
|
service.getSettingsActivity(),
|
||||||
|
/* enforcedCredManAdmin= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -653,7 +658,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
@Nullable Drawable icon,
|
@Nullable Drawable icon,
|
||||||
@NonNull String packageName,
|
@NonNull String packageName,
|
||||||
@Nullable CharSequence subtitle,
|
@Nullable CharSequence subtitle,
|
||||||
@Nullable CharSequence settingsActivity) {
|
@Nullable CharSequence settingsActivity,
|
||||||
|
@Nullable RestrictedLockUtils.EnforcedAdmin enforcedCredManAdmin) {
|
||||||
final CombiPreference pref =
|
final CombiPreference pref =
|
||||||
new CombiPreference(prefContext, mEnabledPackageNames.contains(packageName));
|
new CombiPreference(prefContext, mEnabledPackageNames.contains(packageName));
|
||||||
pref.setTitle(title);
|
pref.setTitle(title);
|
||||||
@@ -669,6 +675,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
pref.setSummary(subtitle);
|
pref.setSummary(subtitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pref.setDisabledByAdmin(enforcedCredManAdmin);
|
||||||
|
|
||||||
pref.setPreferenceListener(
|
pref.setPreferenceListener(
|
||||||
new CombiPreference.OnCombiPreferenceClickListener() {
|
new CombiPreference.OnCombiPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1005,8 +1013,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** CombiPreference is a combination of TwoTargetPreference and SwitchPreference. */
|
/** CombiPreference is a combination of RestrictedPreference and SwitchPreference. */
|
||||||
public static class CombiPreference extends TwoTargetPreference {
|
public static class CombiPreference extends RestrictedPreference {
|
||||||
|
|
||||||
private final Listener mListener = new Listener();
|
private final Listener mListener = new Listener();
|
||||||
|
|
||||||
|
@@ -21,6 +21,9 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageItemInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.credentials.CredentialManager;
|
import android.credentials.CredentialManager;
|
||||||
import android.credentials.CredentialProviderInfo;
|
import android.credentials.CredentialProviderInfo;
|
||||||
@@ -39,14 +42,17 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.internal.content.PackageMonitor;
|
import com.android.internal.content.PackageMonitor;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
|
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
|
||||||
|
import com.android.settingslib.RestrictedSelectorWithWidgetPreference;
|
||||||
import com.android.settingslib.applications.DefaultAppInfo;
|
import com.android.settingslib.applications.DefaultAppInfo;
|
||||||
import com.android.settingslib.widget.CandidateInfo;
|
import com.android.settingslib.widget.CandidateInfo;
|
||||||
|
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -263,7 +269,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
if (service != null) {
|
if (service != null) {
|
||||||
credManProviders.addAll(
|
credManProviders.addAll(
|
||||||
service.getCredentialProviderServices(
|
service.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
|
getUser(),
|
||||||
|
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
final String selectedAutofillProvider = getSelectedAutofillProvider(context, getUser());
|
final String selectedAutofillProvider = getSelectedAutofillProvider(context, getUser());
|
||||||
@@ -283,30 +290,75 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
|
|
||||||
for (CombinedProviderInfo cpi : allProviders) {
|
for (CombinedProviderInfo cpi : allProviders) {
|
||||||
ServiceInfo brandingService = cpi.getBrandingService();
|
ServiceInfo brandingService = cpi.getBrandingService();
|
||||||
if (brandingService == null) {
|
ApplicationInfo appInfo = cpi.getApplicationInfo();
|
||||||
|
|
||||||
|
if (brandingService != null) {
|
||||||
candidates.add(
|
candidates.add(
|
||||||
new DefaultAppInfo(
|
new CredentialManagerDefaultAppInfo(
|
||||||
context,
|
context, mPm, getUser(), brandingService, cpi));
|
||||||
mPm,
|
} else if (appInfo != null) {
|
||||||
getUser(),
|
|
||||||
cpi.getApplicationInfo(),
|
|
||||||
cpi.getSettingsSubtitle(),
|
|
||||||
true));
|
|
||||||
} else {
|
|
||||||
candidates.add(
|
candidates.add(
|
||||||
new DefaultAppInfo(
|
new CredentialManagerDefaultAppInfo(context, mPm, getUser(), appInfo, cpi));
|
||||||
context,
|
|
||||||
mPm,
|
|
||||||
getUser(),
|
|
||||||
brandingService,
|
|
||||||
cpi.getSettingsSubtitle(),
|
|
||||||
true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindPreferenceExtra(
|
||||||
|
SelectorWithWidgetPreference pref,
|
||||||
|
String key,
|
||||||
|
CandidateInfo info,
|
||||||
|
String defaultKey,
|
||||||
|
String systemDefaultKey) {
|
||||||
|
super.bindPreferenceExtra(pref, key, info, defaultKey, systemDefaultKey);
|
||||||
|
|
||||||
|
if (!(info instanceof CredentialManagerDefaultAppInfo)) {
|
||||||
|
Log.e(TAG, "Candidate info should be a subclass of CredentialManagerDefaultAppInfo");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pref instanceof RestrictedSelectorWithWidgetPreference)) {
|
||||||
|
Log.e(TAG, "Preference should be a subclass of RestrictedSelectorWithWidgetPreference");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CredentialManagerDefaultAppInfo credmanAppInfo = (CredentialManagerDefaultAppInfo) info;
|
||||||
|
RestrictedSelectorWithWidgetPreference rp = (RestrictedSelectorWithWidgetPreference) pref;
|
||||||
|
|
||||||
|
// Apply policy transparency.
|
||||||
|
rp.setDisabledByAdmin(
|
||||||
|
credmanAppInfo
|
||||||
|
.getCombinedProviderInfo()
|
||||||
|
.getDeviceAdminRestrictions(getContext(), getUser()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SelectorWithWidgetPreference createPreference() {
|
||||||
|
return new RestrictedSelectorWithWidgetPreference(getPrefContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This extends DefaultAppInfo with custom CredMan app info. */
|
||||||
|
public static class CredentialManagerDefaultAppInfo extends DefaultAppInfo {
|
||||||
|
|
||||||
|
private final CombinedProviderInfo mCombinedProviderInfo;
|
||||||
|
|
||||||
|
CredentialManagerDefaultAppInfo(
|
||||||
|
Context context,
|
||||||
|
PackageManager pm,
|
||||||
|
int uid,
|
||||||
|
PackageItemInfo info,
|
||||||
|
CombinedProviderInfo cpi) {
|
||||||
|
super(context, pm, uid, info, cpi.getSettingsSubtitle(), /* enabled= */ true);
|
||||||
|
mCombinedProviderInfo = cpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull CombinedProviderInfo getCombinedProviderInfo() {
|
||||||
|
return mCombinedProviderInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDefaultKey() {
|
protected String getDefaultKey() {
|
||||||
final CombinedProviderInfo topProvider =
|
final CombinedProviderInfo topProvider =
|
||||||
@@ -415,7 +467,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
final List<String> credManProviders = new ArrayList<>();
|
final List<String> credManProviders = new ArrayList<>();
|
||||||
for (CredentialProviderInfo cpi :
|
for (CredentialProviderInfo cpi :
|
||||||
service.getCredentialProviderServices(
|
service.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)) {
|
getUser(),
|
||||||
|
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN)) {
|
||||||
|
|
||||||
if (cpi.isEnabled() && !cpi.isPrimary()) {
|
if (cpi.isEnabled() && !cpi.isPrimary()) {
|
||||||
credManProviders.add(cpi.getServiceInfo().getComponentName().flattenToString());
|
credManProviders.add(cpi.getServiceInfo().getComponentName().flattenToString());
|
||||||
|
@@ -111,7 +111,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
|
|||||||
@Nullable CharSequence appName,
|
@Nullable CharSequence appName,
|
||||||
@Nullable String appSubtitle,
|
@Nullable String appSubtitle,
|
||||||
@Nullable Drawable appIcon,
|
@Nullable Drawable appIcon,
|
||||||
@Nullable CharSequence packageName,
|
@Nullable String packageName,
|
||||||
@Nullable CharSequence settingsActivity) {
|
@Nullable CharSequence settingsActivity) {
|
||||||
if (appName == null) {
|
if (appName == null) {
|
||||||
preference.setTitle(R.string.credman_app_list_preference_none);
|
preference.setTitle(R.string.credman_app_list_preference_none);
|
||||||
|
@@ -159,6 +159,13 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme
|
|||||||
String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
|
String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A chance for subclasses to create a custom preference instance.
|
||||||
|
*/
|
||||||
|
protected SelectorWithWidgetPreference createPreference() {
|
||||||
|
return new SelectorWithWidgetPreference(getPrefContext());
|
||||||
|
}
|
||||||
|
|
||||||
public void updateCandidates() {
|
public void updateCandidates() {
|
||||||
mCandidates.clear();
|
mCandidates.clear();
|
||||||
final List<? extends CandidateInfo> candidateList = getCandidates();
|
final List<? extends CandidateInfo> candidateList = getCandidates();
|
||||||
@@ -193,8 +200,7 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme
|
|||||||
}
|
}
|
||||||
if (candidateList != null) {
|
if (candidateList != null) {
|
||||||
for (CandidateInfo info : candidateList) {
|
for (CandidateInfo info : candidateList) {
|
||||||
SelectorWithWidgetPreference pref =
|
SelectorWithWidgetPreference pref = createPreference();
|
||||||
new SelectorWithWidgetPreference(getPrefContext());
|
|
||||||
if (customLayoutResId > 0) {
|
if (customLayoutResId > 0) {
|
||||||
pref.setLayoutResource(customLayoutResId);
|
pref.setLayoutResource(customLayoutResId);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user