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.Nullable;
|
||||
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -236,6 +239,31 @@ public final class CombinedProviderInfo {
|
||||
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. */
|
||||
public static @Nullable CombinedProviderInfo getTopProvider(
|
||||
List<CombinedProviderInfo> providers) {
|
||||
@@ -327,8 +355,7 @@ public final class CombinedProviderInfo {
|
||||
}
|
||||
|
||||
public static @Nullable Intent createSettingsActivityIntent(
|
||||
@Nullable CharSequence packageName,
|
||||
@Nullable CharSequence settingsActivity) {
|
||||
@Nullable CharSequence packageName, @Nullable CharSequence settingsActivity) {
|
||||
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(settingsActivity)) {
|
||||
return null;
|
||||
}
|
||||
|
@@ -69,8 +69,9 @@ import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
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.widget.TwoTargetPreference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -328,7 +329,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
|
||||
setAvailableServices(
|
||||
mCredentialManager.getCredentialProviderServices(
|
||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
|
||||
getUser(),
|
||||
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN),
|
||||
null);
|
||||
}
|
||||
|
||||
@@ -355,7 +357,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
// Get the list of new providers and components.
|
||||
List<CredentialProviderInfo> newProviders =
|
||||
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> newPrimaryComponents = buildComponentNameSet(newProviders, true);
|
||||
|
||||
@@ -548,7 +551,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
icon,
|
||||
packageName,
|
||||
combinedInfo.getSettingsSubtitle(),
|
||||
combinedInfo.getSettingsActivity());
|
||||
combinedInfo.getSettingsActivity(),
|
||||
combinedInfo.getDeviceAdminRestrictions(context, getUser()));
|
||||
output.put(packageName, pref);
|
||||
group.addPreference(pref);
|
||||
}
|
||||
@@ -569,7 +573,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
service.getServiceIcon(mContext),
|
||||
service.getServiceInfo().packageName,
|
||||
service.getSettingsSubtitle(),
|
||||
service.getSettingsActivity());
|
||||
service.getSettingsActivity(),
|
||||
/* enforcedCredManAdmin= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -653,7 +658,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
@Nullable Drawable icon,
|
||||
@NonNull String packageName,
|
||||
@Nullable CharSequence subtitle,
|
||||
@Nullable CharSequence settingsActivity) {
|
||||
@Nullable CharSequence settingsActivity,
|
||||
@Nullable RestrictedLockUtils.EnforcedAdmin enforcedCredManAdmin) {
|
||||
final CombiPreference pref =
|
||||
new CombiPreference(prefContext, mEnabledPackageNames.contains(packageName));
|
||||
pref.setTitle(title);
|
||||
@@ -669,6 +675,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
pref.setSummary(subtitle);
|
||||
}
|
||||
|
||||
pref.setDisabledByAdmin(enforcedCredManAdmin);
|
||||
|
||||
pref.setPreferenceListener(
|
||||
new CombiPreference.OnCombiPreferenceClickListener() {
|
||||
@Override
|
||||
@@ -1005,8 +1013,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
||||
}
|
||||
}
|
||||
|
||||
/** CombiPreference is a combination of TwoTargetPreference and SwitchPreference. */
|
||||
public static class CombiPreference extends TwoTargetPreference {
|
||||
/** CombiPreference is a combination of RestrictedPreference and SwitchPreference. */
|
||||
public static class CombiPreference extends RestrictedPreference {
|
||||
|
||||
private final Listener mListener = new Listener();
|
||||
|
||||
|
@@ -21,6 +21,9 @@ import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
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.credentials.CredentialManager;
|
||||
import android.credentials.CredentialProviderInfo;
|
||||
@@ -39,14 +42,17 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
|
||||
import com.android.settingslib.RestrictedSelectorWithWidgetPreference;
|
||||
import com.android.settingslib.applications.DefaultAppInfo;
|
||||
import com.android.settingslib.widget.CandidateInfo;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -263,7 +269,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
||||
if (service != null) {
|
||||
credManProviders.addAll(
|
||||
service.getCredentialProviderServices(
|
||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
|
||||
getUser(),
|
||||
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN));
|
||||
}
|
||||
|
||||
final String selectedAutofillProvider = getSelectedAutofillProvider(context, getUser());
|
||||
@@ -283,30 +290,75 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
||||
|
||||
for (CombinedProviderInfo cpi : allProviders) {
|
||||
ServiceInfo brandingService = cpi.getBrandingService();
|
||||
if (brandingService == null) {
|
||||
ApplicationInfo appInfo = cpi.getApplicationInfo();
|
||||
|
||||
if (brandingService != null) {
|
||||
candidates.add(
|
||||
new DefaultAppInfo(
|
||||
context,
|
||||
mPm,
|
||||
getUser(),
|
||||
cpi.getApplicationInfo(),
|
||||
cpi.getSettingsSubtitle(),
|
||||
true));
|
||||
} else {
|
||||
new CredentialManagerDefaultAppInfo(
|
||||
context, mPm, getUser(), brandingService, cpi));
|
||||
} else if (appInfo != null) {
|
||||
candidates.add(
|
||||
new DefaultAppInfo(
|
||||
context,
|
||||
mPm,
|
||||
getUser(),
|
||||
brandingService,
|
||||
cpi.getSettingsSubtitle(),
|
||||
true));
|
||||
new CredentialManagerDefaultAppInfo(context, mPm, getUser(), appInfo, cpi));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
protected String getDefaultKey() {
|
||||
final CombinedProviderInfo topProvider =
|
||||
@@ -415,7 +467,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
||||
final List<String> credManProviders = new ArrayList<>();
|
||||
for (CredentialProviderInfo cpi :
|
||||
service.getCredentialProviderServices(
|
||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)) {
|
||||
getUser(),
|
||||
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN)) {
|
||||
|
||||
if (cpi.isEnabled() && !cpi.isPrimary()) {
|
||||
credManProviders.add(cpi.getServiceInfo().getComponentName().flattenToString());
|
||||
|
@@ -111,7 +111,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
|
||||
@Nullable CharSequence appName,
|
||||
@Nullable String appSubtitle,
|
||||
@Nullable Drawable appIcon,
|
||||
@Nullable CharSequence packageName,
|
||||
@Nullable String packageName,
|
||||
@Nullable CharSequence settingsActivity) {
|
||||
if (appName == null) {
|
||||
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) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A chance for subclasses to create a custom preference instance.
|
||||
*/
|
||||
protected SelectorWithWidgetPreference createPreference() {
|
||||
return new SelectorWithWidgetPreference(getPrefContext());
|
||||
}
|
||||
|
||||
public void updateCandidates() {
|
||||
mCandidates.clear();
|
||||
final List<? extends CandidateInfo> candidateList = getCandidates();
|
||||
@@ -193,8 +200,7 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme
|
||||
}
|
||||
if (candidateList != null) {
|
||||
for (CandidateInfo info : candidateList) {
|
||||
SelectorWithWidgetPreference pref =
|
||||
new SelectorWithWidgetPreference(getPrefContext());
|
||||
SelectorWithWidgetPreference pref = createPreference();
|
||||
if (customLayoutResId > 0) {
|
||||
pref.setLayoutResource(customLayoutResId);
|
||||
}
|
||||
|
Reference in New Issue
Block a user