Align settings with new mocks
Test: ondevice Bug: 278919696 Change-Id: I274126bce3616596c4a81dd3385f0844d8bdbf71
This commit is contained in:
@@ -237,7 +237,10 @@ public final class CombinedProviderInfo {
|
|||||||
List<CredentialProviderInfo> cpi = credmanServices.get(packageName);
|
List<CredentialProviderInfo> cpi = credmanServices.get(packageName);
|
||||||
|
|
||||||
// If there are multiple autofill services then pick the first one.
|
// If there are multiple autofill services then pick the first one.
|
||||||
AutofillServiceInfo selectedAsi = asi.isEmpty() ? null : asi.get(0);
|
AutofillServiceInfo selectedAsi = null;
|
||||||
|
if (asi != null && !asi.isEmpty()) {
|
||||||
|
selectedAsi = asi.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we are the default autofill provider.
|
// Check if we are the default autofill provider.
|
||||||
boolean isDefaultAutofillProvider = false;
|
boolean isDefaultAutofillProvider = false;
|
||||||
|
@@ -41,8 +41,8 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.OutcomeReceiver;
|
import android.os.OutcomeReceiver;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.service.autofill.AutofillServiceInfo;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.IconDrawableFactory;
|
import android.util.IconDrawableFactory;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -79,6 +79,15 @@ import java.util.concurrent.Executor;
|
|||||||
public class CredentialManagerPreferenceController extends BasePreferenceController
|
public class CredentialManagerPreferenceController extends BasePreferenceController
|
||||||
implements LifecycleObserver {
|
implements LifecycleObserver {
|
||||||
public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
|
public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the settings logic we should hide the list of additional credman providers if there is no
|
||||||
|
* provider selected at the top. The current logic relies on checking whether the autofill
|
||||||
|
* provider is set which won't work for cred-man only providers. Therefore when a CM only
|
||||||
|
* provider is set we will set the autofill setting to be this placeholder.
|
||||||
|
*/
|
||||||
|
public static final String AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER = "credential-provider";
|
||||||
|
|
||||||
private static final String TAG = "CredentialManagerPreferenceController";
|
private static final String TAG = "CredentialManagerPreferenceController";
|
||||||
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
||||||
private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
|
private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
|
||||||
@@ -99,6 +108,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
private @Nullable String mFlagOverrideForTest = null;
|
private @Nullable String mFlagOverrideForTest = null;
|
||||||
private @Nullable PreferenceScreen mPreferenceScreen = null;
|
private @Nullable PreferenceScreen mPreferenceScreen = null;
|
||||||
|
|
||||||
|
private boolean mVisibility = false;
|
||||||
|
|
||||||
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
|
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
mPm = context.getPackageManager();
|
mPm = context.getPackageManager();
|
||||||
@@ -131,7 +142,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
return UNSUPPORTED_ON_DEVICE;
|
return UNSUPPORTED_ON_DEVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAutofillPrefSelected()) {
|
if (!mVisibility) {
|
||||||
return CONDITIONALLY_UNAVAILABLE;
|
return CONDITIONALLY_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +282,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
|
|
||||||
setAvailableServices(
|
setAvailableServices(
|
||||||
mCredentialManager.getCredentialProviderServices(
|
mCredentialManager.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
|
getUser(), CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +298,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setVisibility(boolean newVisibility) {
|
||||||
|
if (newVisibility == mVisibility) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mVisibility = newVisibility;
|
||||||
|
if (mDelegate != null) {
|
||||||
|
mDelegate.forceDelegateRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setAvailableServices(
|
void setAvailableServices(
|
||||||
List<CredentialProviderInfo> availableServices, String flagOverrideForTest) {
|
List<CredentialProviderInfo> availableServices, String flagOverrideForTest) {
|
||||||
@@ -320,48 +342,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
||||||
group.removeAll();
|
group.removeAll();
|
||||||
|
|
||||||
// Hide/show based on autofill pref.
|
|
||||||
boolean isVisible = isAutofillPrefSelected();
|
|
||||||
screen.setVisible(isVisible);
|
|
||||||
group.setVisible(isVisible);
|
|
||||||
|
|
||||||
if (!isVisible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Context context = screen.getContext();
|
Context context = screen.getContext();
|
||||||
mPrefs.putAll(buildPreferenceList(context, group));
|
mPrefs.putAll(buildPreferenceList(context, group));
|
||||||
|
|
||||||
// Add the "add service" button only when there are no providers.
|
|
||||||
if (mPrefs.isEmpty()) {
|
|
||||||
String searchUri = getAddServiceUri(context);
|
|
||||||
if (!TextUtils.isEmpty(searchUri)) {
|
|
||||||
group.addPreference(newAddServicePreference(searchUri, context));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the "add service" URI to show the play store. It will first try and use the
|
|
||||||
* credential manager specific search URI and if that is null it will fallback to the autofill
|
|
||||||
* one.
|
|
||||||
*/
|
|
||||||
public @NonNull String getAddServiceUri(@NonNull Context context) {
|
|
||||||
// Check the credential manager gflag for a link.
|
|
||||||
String searchUri =
|
|
||||||
DeviceConfig.getString(
|
|
||||||
DeviceConfig.NAMESPACE_CREDENTIAL,
|
|
||||||
ADD_SERVICE_DEVICE_CONFIG,
|
|
||||||
mFlagOverrideForTest);
|
|
||||||
if (!TextUtils.isEmpty(searchUri)) {
|
|
||||||
return searchUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not fall back on autofill.
|
|
||||||
return Settings.Secure.getStringForUser(
|
|
||||||
context.getContentResolver(),
|
|
||||||
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
|
|
||||||
getUser());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,52 +378,59 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Map<String, SwitchPreference> buildPreferenceList(
|
public Map<String, SwitchPreference> buildPreferenceList(
|
||||||
Context context, PreferenceGroup group) {
|
Context context, PreferenceGroup group) {
|
||||||
// Group the services by package name.
|
// Get the selected autofill provider. If it is the placeholder then replace it with an
|
||||||
Map<String, List<CredentialProviderInfo>> groupedInfos = new HashMap<>();
|
// empty string.
|
||||||
for (CredentialProviderInfo cpi : mServices) {
|
String selectedAutofillProvider =
|
||||||
String packageName = cpi.getServiceInfo().packageName;
|
DefaultCombinedPicker.getSelectedAutofillProvider(mContext, getUser());
|
||||||
if (isProviderHiddenBecauseOfAutofill(packageName)) {
|
if (TextUtils.equals(
|
||||||
|
selectedAutofillProvider, AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER)) {
|
||||||
|
selectedAutofillProvider = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of combined providers.
|
||||||
|
List<CombinedProviderInfo> providers =
|
||||||
|
CombinedProviderInfo.buildMergedList(
|
||||||
|
AutofillServiceInfo.getAvailableServices(context, getUser()),
|
||||||
|
mServices,
|
||||||
|
selectedAutofillProvider);
|
||||||
|
|
||||||
|
// Get the provider that is displayed at the top. If there is none then hide
|
||||||
|
// everything.
|
||||||
|
CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
|
||||||
|
if (topProvider == null) {
|
||||||
|
setVisibility(false);
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, SwitchPreference> output = new HashMap<>();
|
||||||
|
for (CombinedProviderInfo combinedInfo : providers) {
|
||||||
|
final String packageName = combinedInfo.getApplicationInfo().packageName;
|
||||||
|
|
||||||
|
// If this provider is displayed at the top then we should not show it.
|
||||||
|
if (topProvider != null
|
||||||
|
&& topProvider.getApplicationInfo().packageName.equals(packageName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!groupedInfos.containsKey(packageName)) {
|
// If this is an autofill provider then don't show it here.
|
||||||
groupedInfos.put(packageName, new ArrayList<>());
|
if (combinedInfo.getCredentialProviderInfos().isEmpty()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedInfos.get(packageName).add(cpi);
|
Drawable icon = combinedInfo.getAppIcon(context);
|
||||||
}
|
CharSequence title = combinedInfo.getAppName(context);
|
||||||
|
|
||||||
// Build the pref list.
|
|
||||||
Map<String, SwitchPreference> output = new HashMap<>();
|
|
||||||
for (String packageName : groupedInfos.keySet()) {
|
|
||||||
List<CredentialProviderInfo> infos = groupedInfos.get(packageName);
|
|
||||||
CredentialProviderInfo firstInfo = infos.get(0);
|
|
||||||
ServiceInfo firstServiceInfo = firstInfo.getServiceInfo();
|
|
||||||
CharSequence title = firstInfo.getLabel(context);
|
|
||||||
Drawable icon = firstInfo.getServiceIcon(context);
|
|
||||||
|
|
||||||
if (infos.size() > 1) {
|
|
||||||
// If there is more than one then group them under the package.
|
|
||||||
ApplicationInfo appInfo = firstServiceInfo.applicationInfo;
|
|
||||||
if (appInfo.nonLocalizedLabel != null) {
|
|
||||||
title = appInfo.loadLabel(mPm);
|
|
||||||
}
|
|
||||||
icon = mIconFactory.getBadgedIcon(appInfo, getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no title then show the package manager.
|
|
||||||
if (TextUtils.isEmpty(title)) {
|
|
||||||
title = firstServiceInfo.packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the pref and add it to the output & group.
|
// Build the pref and add it to the output & group.
|
||||||
SwitchPreference pref =
|
SwitchPreference pref =
|
||||||
addProviderPreference(
|
addProviderPreference(
|
||||||
context, title, icon, packageName, firstInfo.getSettingsSubtitle());
|
context, title, icon, packageName, combinedInfo.getSettingsSubtitle());
|
||||||
output.put(packageName, pref);
|
output.put(packageName, pref);
|
||||||
group.addPreference(pref);
|
group.addPreference(pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the visibility if we have services.
|
||||||
|
setVisibility(!output.isEmpty());
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,29 +596,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
return new NewProviderConfirmationDialogFragment(host, packageName, appName);
|
return new NewProviderConfirmationDialogFragment(host, packageName, appName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If the provider is also the autofill provider then hide it. */
|
|
||||||
@VisibleForTesting
|
|
||||||
public boolean isProviderHiddenBecauseOfAutofill(String packageName) {
|
|
||||||
final String autofillService =
|
|
||||||
Settings.Secure.getStringForUser(
|
|
||||||
mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser());
|
|
||||||
if (autofillService == null || TextUtils.isEmpty(autofillService)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (packageName == null || TextUtils.isEmpty(packageName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return autofillService.startsWith(packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAutofillPrefSelected() {
|
|
||||||
final String autofillService =
|
|
||||||
Settings.Secure.getStringForUser(
|
|
||||||
mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser());
|
|
||||||
return !TextUtils.isEmpty(autofillService);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void completeEnableProviderDialogBox(
|
void completeEnableProviderDialogBox(
|
||||||
int whichButton, String packageName, boolean setActivityResult) {
|
int whichButton, String packageName, boolean setActivityResult) {
|
||||||
|
@@ -16,21 +16,27 @@
|
|||||||
|
|
||||||
package com.android.settings.applications.credentials;
|
package com.android.settings.applications.credentials;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.ComponentName;
|
|
||||||
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.ServiceInfo;
|
||||||
|
import android.credentials.CredentialManager;
|
||||||
|
import android.credentials.CredentialProviderInfo;
|
||||||
|
import android.credentials.SetEnabledProvidersException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.OutcomeReceiver;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.autofill.AutofillService;
|
|
||||||
import android.service.autofill.AutofillServiceInfo;
|
import android.service.autofill.AutofillServiceInfo;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -47,8 +53,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
|
|
||||||
private static final String TAG = "DefaultCombinedPicker";
|
private static final String TAG = "DefaultCombinedPicker";
|
||||||
|
|
||||||
public static final String SETTING = Settings.Secure.AUTOFILL_SERVICE;
|
public static final String AUTOFILL_SETTING = Settings.Secure.AUTOFILL_SERVICE;
|
||||||
public static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
|
public static final String CREDENTIAL_SETTING = Settings.Secure.CREDENTIAL_SERVICE;
|
||||||
|
|
||||||
/** Extra set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
|
/** Extra set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
|
||||||
public static final String EXTRA_PACKAGE_NAME = "package_name";
|
public static final String EXTRA_PACKAGE_NAME = "package_name";
|
||||||
@@ -56,6 +62,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
/** Set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
|
/** Set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
|
||||||
private DialogInterface.OnClickListener mCancelListener;
|
private DialogInterface.OnClickListener mCancelListener;
|
||||||
|
|
||||||
|
private CredentialManager mCredentialManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -71,6 +79,7 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
// ACTION_REQUEST_SET_AUTOFILL_SERVICE and we should always use the calling uid.
|
// ACTION_REQUEST_SET_AUTOFILL_SERVICE and we should always use the calling uid.
|
||||||
mUserId = UserHandle.myUserId();
|
mUserId = UserHandle.myUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
mSettingsPackageMonitor.register(activity, activity.getMainLooper(), false);
|
mSettingsPackageMonitor.register(activity, activity.getMainLooper(), false);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -187,35 +196,76 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* Get the Credential Manager service if we haven't already got it. We need to get the service
|
||||||
|
* later because if we do it in onCreate it will fail.
|
||||||
|
*/
|
||||||
|
private @Nullable CredentialManager getCredentialProviderService() {
|
||||||
|
if (mCredentialManager == null) {
|
||||||
|
mCredentialManager = getContext().getSystemService(CredentialManager.class);
|
||||||
|
}
|
||||||
|
return mCredentialManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CombinedProviderInfo> getAllProviders() {
|
||||||
|
final Context context = getContext();
|
||||||
|
final List<AutofillServiceInfo> autofillProviders =
|
||||||
|
AutofillServiceInfo.getAvailableServices(context, mUserId);
|
||||||
|
|
||||||
|
final CredentialManager service = getCredentialProviderService();
|
||||||
|
final List<CredentialProviderInfo> credManProviders = new ArrayList<>();
|
||||||
|
if (service != null) {
|
||||||
|
credManProviders.addAll(
|
||||||
|
service.getCredentialProviderServices(
|
||||||
|
mUserId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
|
||||||
|
}
|
||||||
|
|
||||||
|
final String selectedAutofillProvider = getSelectedAutofillProvider(context, mUserId);
|
||||||
|
return CombinedProviderInfo.buildMergedList(
|
||||||
|
autofillProviders, credManProviders, selectedAutofillProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSelectedAutofillProvider(Context context, int userId) {
|
||||||
|
return Settings.Secure.getStringForUser(
|
||||||
|
context.getContentResolver(), AUTOFILL_SETTING, userId);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<DefaultAppInfo> getCandidates() {
|
protected List<DefaultAppInfo> getCandidates() {
|
||||||
|
final Context context = getContext();
|
||||||
|
final List<CombinedProviderInfo> allProviders = getAllProviders();
|
||||||
final List<DefaultAppInfo> candidates = new ArrayList<>();
|
final List<DefaultAppInfo> candidates = new ArrayList<>();
|
||||||
final List<AutofillServiceInfo> services =
|
|
||||||
AutofillServiceInfo.getAvailableServices(getContext(), mUserId);
|
for (CombinedProviderInfo cpi : allProviders) {
|
||||||
for (AutofillServiceInfo asi : services) {
|
ServiceInfo brandingService = cpi.getBrandingService();
|
||||||
|
if (brandingService == null) {
|
||||||
candidates.add(
|
candidates.add(
|
||||||
new DefaultAppInfo(
|
new DefaultAppInfo(
|
||||||
getContext(), mPm, mUserId, asi.getServiceInfo().getComponentName()));
|
context,
|
||||||
|
mPm,
|
||||||
|
mUserId,
|
||||||
|
cpi.getApplicationInfo(),
|
||||||
|
cpi.getSettingsSubtitle(),
|
||||||
|
true));
|
||||||
|
} else {
|
||||||
|
candidates.add(
|
||||||
|
new DefaultAppInfo(
|
||||||
|
context,
|
||||||
|
mPm,
|
||||||
|
mUserId,
|
||||||
|
brandingService,
|
||||||
|
cpi.getSettingsSubtitle(),
|
||||||
|
true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDefaultKey(Context context, int userId) {
|
|
||||||
String setting =
|
|
||||||
Settings.Secure.getStringForUser(context.getContentResolver(), SETTING, userId);
|
|
||||||
if (setting != null) {
|
|
||||||
ComponentName componentName = ComponentName.unflattenFromString(setting);
|
|
||||||
if (componentName != null) {
|
|
||||||
return componentName.flattenToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDefaultKey() {
|
protected String getDefaultKey() {
|
||||||
return getDefaultKey(getContext(), mUserId);
|
final CombinedProviderInfo topProvider =
|
||||||
|
CombinedProviderInfo.getTopProvider(getAllProviders());
|
||||||
|
return topProvider == null ? "" : topProvider.getApplicationInfo().packageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -234,7 +284,39 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean setDefaultKey(String key) {
|
protected boolean setDefaultKey(String key) {
|
||||||
Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING, key, mUserId);
|
// Get the list of providers and see if any match the key (package name).
|
||||||
|
final List<CombinedProviderInfo> allProviders = getAllProviders();
|
||||||
|
CombinedProviderInfo matchedProvider = null;
|
||||||
|
for (CombinedProviderInfo cpi : allProviders) {
|
||||||
|
if (cpi.getApplicationInfo().packageName.equals(key)) {
|
||||||
|
matchedProvider = cpi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there were none then clear the stored providers.
|
||||||
|
if (matchedProvider == null) {
|
||||||
|
setProviders(null, new ArrayList<>());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the component names and save them.
|
||||||
|
final List<String> credManComponents = new ArrayList<>();
|
||||||
|
for (CredentialProviderInfo pi : matchedProvider.getCredentialProviderInfos()) {
|
||||||
|
credManComponents.add(pi.getServiceInfo().getComponentName().flattenToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String autofillValue = null;
|
||||||
|
if (matchedProvider.getAutofillServiceInfo() != null) {
|
||||||
|
autofillValue =
|
||||||
|
matchedProvider
|
||||||
|
.getAutofillServiceInfo()
|
||||||
|
.getServiceInfo()
|
||||||
|
.getComponentName()
|
||||||
|
.flattenToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
setProviders(autofillValue, credManComponents);
|
||||||
|
|
||||||
// Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
|
// Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
|
||||||
// intent, and set proper result if so...
|
// intent, and set proper result if so...
|
||||||
@@ -255,4 +337,38 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setProviders(String autofillProvider, List<String> credManProviders) {
|
||||||
|
if (TextUtils.isEmpty(autofillProvider)) {
|
||||||
|
if (credManProviders.size() > 0) {
|
||||||
|
autofillProvider =
|
||||||
|
CredentialManagerPreferenceController
|
||||||
|
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.Secure.putStringForUser(
|
||||||
|
getContext().getContentResolver(), AUTOFILL_SETTING, autofillProvider, mUserId);
|
||||||
|
|
||||||
|
CredentialManager service = getCredentialProviderService();
|
||||||
|
if (service == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
service.setEnabledProviders(
|
||||||
|
credManProviders,
|
||||||
|
mUserId,
|
||||||
|
ContextCompat.getMainExecutor(getContext()),
|
||||||
|
new OutcomeReceiver<Void, SetEnabledProvidersException>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(Void result) {
|
||||||
|
Log.i(TAG, "setEnabledProviders success");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(SetEnabledProvidersException e) {
|
||||||
|
Log.e(TAG, "setEnabledProviders error: " + e.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,9 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.credentials.CredentialManager;
|
import android.credentials.CredentialManager;
|
||||||
|
import android.credentials.CredentialProviderInfo;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.service.autofill.AutofillService;
|
||||||
import android.service.autofill.AutofillServiceInfo;
|
import android.service.autofill.AutofillServiceInfo;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -36,6 +38,9 @@ import java.util.List;
|
|||||||
|
|
||||||
public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {
|
public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {
|
||||||
|
|
||||||
|
private static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
|
||||||
|
private static final String TAG = "DefaultCombinedPreferenceController";
|
||||||
|
|
||||||
private final AutofillManager mAutofillManager;
|
private final AutofillManager mAutofillManager;
|
||||||
private final CredentialManager mCredentialManager;
|
private final CredentialManager mCredentialManager;
|
||||||
|
|
||||||
@@ -76,26 +81,57 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DefaultAppInfo getDefaultAppInfo() {
|
protected DefaultAppInfo getDefaultAppInfo() {
|
||||||
final String flattenComponent =
|
List<CombinedProviderInfo> providers = getAllProviders(mUserId);
|
||||||
Settings.Secure.getString(
|
CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
|
||||||
mContext.getContentResolver(), DefaultCombinedPicker.SETTING);
|
if (topProvider != null) {
|
||||||
if (!TextUtils.isEmpty(flattenComponent)) {
|
ServiceInfo brandingService = topProvider.getBrandingService();
|
||||||
DefaultAppInfo appInfo =
|
if (brandingService == null) {
|
||||||
new DefaultAppInfo(
|
return new DefaultAppInfo(
|
||||||
mContext,
|
mContext,
|
||||||
mPackageManager,
|
mPackageManager,
|
||||||
mUserId,
|
mUserId,
|
||||||
ComponentName.unflattenFromString(flattenComponent));
|
topProvider.getApplicationInfo(),
|
||||||
return appInfo;
|
topProvider.getSettingsSubtitle(),
|
||||||
|
true);
|
||||||
|
} else {
|
||||||
|
return new DefaultAppInfo(
|
||||||
|
mContext,
|
||||||
|
mPackageManager,
|
||||||
|
mUserId,
|
||||||
|
brandingService,
|
||||||
|
topProvider.getSettingsSubtitle(),
|
||||||
|
true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CombinedProviderInfo> getAllProviders(int userId) {
|
||||||
|
final List<AutofillServiceInfo> autofillProviders =
|
||||||
|
AutofillServiceInfo.getAvailableServices(mContext, userId);
|
||||||
|
final List<CredentialProviderInfo> credManProviders =
|
||||||
|
mCredentialManager.getCredentialProviderServices(
|
||||||
|
userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
|
||||||
|
final String selectedAutofillProvider =
|
||||||
|
Settings.Secure.getStringForUser(
|
||||||
|
mContext.getContentResolver(),
|
||||||
|
DefaultCombinedPicker.AUTOFILL_SETTING,
|
||||||
|
userId);
|
||||||
|
|
||||||
|
return CombinedProviderInfo.buildMergedList(
|
||||||
|
autofillProviders, credManProviders, selectedAutofillProvider);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean showLabelAsTitle() {
|
protected boolean showLabelAsTitle() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean showAppSummary() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Provides Intent to setting activity for the specified autofill service. */
|
/** Provides Intent to setting activity for the specified autofill service. */
|
||||||
static final class AutofillSettingIntentProvider {
|
static final class AutofillSettingIntentProvider {
|
||||||
|
|
||||||
@@ -113,9 +149,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
|
|||||||
final List<ResolveInfo> resolveInfos =
|
final List<ResolveInfo> resolveInfos =
|
||||||
mContext.getPackageManager()
|
mContext.getPackageManager()
|
||||||
.queryIntentServicesAsUser(
|
.queryIntentServicesAsUser(
|
||||||
DefaultCombinedPicker.AUTOFILL_PROBE,
|
AUTOFILL_PROBE, PackageManager.GET_META_DATA, mUserId);
|
||||||
PackageManager.GET_META_DATA,
|
|
||||||
mUserId);
|
|
||||||
|
|
||||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||||
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||||
@@ -130,9 +164,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
|
|||||||
.getSettingsActivity();
|
.getSettingsActivity();
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
// Service does not declare the proper permission, ignore it.
|
// Service does not declare the proper permission, ignore it.
|
||||||
Log.w(
|
Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
|
||||||
"AutofillSettingIntentProvider",
|
|
||||||
"Error getting info for " + serviceInfo + ": " + e);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(settingsActivity)) {
|
if (TextUtils.isEmpty(settingsActivity)) {
|
||||||
|
@@ -52,7 +52,7 @@ public class DefaultWorkCombinedPreferenceController extends DefaultCombinedPref
|
|||||||
final String flattenComponent =
|
final String flattenComponent =
|
||||||
Settings.Secure.getStringForUser(
|
Settings.Secure.getStringForUser(
|
||||||
mContext.getContentResolver(),
|
mContext.getContentResolver(),
|
||||||
DefaultCombinedPicker.SETTING,
|
DefaultCombinedPicker.AUTOFILL_SETTING,
|
||||||
mUserHandle.getIdentifier());
|
mUserHandle.getIdentifier());
|
||||||
if (!TextUtils.isEmpty(flattenComponent)) {
|
if (!TextUtils.isEmpty(flattenComponent)) {
|
||||||
DefaultAppInfo appInfo =
|
DefaultAppInfo appInfo =
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.applications.defaultapps;
|
|||||||
|
|
||||||
import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
|
import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -65,16 +66,21 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC
|
|||||||
((TwoTargetPreference) preference).setIconSize(ICON_SIZE_MEDIUM);
|
((TwoTargetPreference) preference).setIconSize(ICON_SIZE_MEDIUM);
|
||||||
}
|
}
|
||||||
if (!TextUtils.isEmpty(defaultAppLabel)) {
|
if (!TextUtils.isEmpty(defaultAppLabel)) {
|
||||||
if (showLabelAsTitle()) {
|
if (showLabelAsTitle() && showAppSummary()) {
|
||||||
|
preference.setTitle(defaultAppLabel);
|
||||||
|
preference.setSummary(getDefaultAppSummary());
|
||||||
|
} else if (showLabelAsTitle()) {
|
||||||
preference.setTitle(defaultAppLabel);
|
preference.setTitle(defaultAppLabel);
|
||||||
} else {
|
} else {
|
||||||
preference.setSummary(defaultAppLabel);
|
preference.setSummary(defaultAppLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
preference.setIcon(Utils.getSafeIcon(getDefaultAppIcon()));
|
preference.setIcon(Utils.getSafeIcon(getDefaultAppIcon()));
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "No default app");
|
Log.d(TAG, "No default app");
|
||||||
if (showLabelAsTitle()) {
|
if (showLabelAsTitle()) {
|
||||||
preference.setTitle(R.string.app_list_preference_none);
|
preference.setTitle(R.string.app_list_preference_none);
|
||||||
|
preference.setSummary(null);
|
||||||
} else {
|
} else {
|
||||||
preference.setSummary(R.string.app_list_preference_none);
|
preference.setSummary(R.string.app_list_preference_none);
|
||||||
}
|
}
|
||||||
@@ -89,8 +95,7 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC
|
|||||||
}
|
}
|
||||||
final Intent settingIntent = getSettingIntent(app);
|
final Intent settingIntent = getSettingIntent(app);
|
||||||
if (settingIntent != null) {
|
if (settingIntent != null) {
|
||||||
((GearPreference) preference).setOnGearClickListener(
|
((GearPreference) preference).setOnGearClickListener(p -> startActivity(settingIntent));
|
||||||
p -> startActivity(settingIntent));
|
|
||||||
} else {
|
} else {
|
||||||
((GearPreference) preference).setOnGearClickListener(null);
|
((GearPreference) preference).setOnGearClickListener(null);
|
||||||
}
|
}
|
||||||
@@ -102,21 +107,22 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC
|
|||||||
|
|
||||||
protected abstract DefaultAppInfo getDefaultAppInfo();
|
protected abstract DefaultAppInfo getDefaultAppInfo();
|
||||||
|
|
||||||
/**
|
/** Returns an optional intent that will be launched when clicking "gear" icon. */
|
||||||
* Returns an optional intent that will be launched when clicking "gear" icon.
|
|
||||||
*/
|
|
||||||
protected Intent getSettingIntent(DefaultAppInfo info) {
|
protected Intent getSettingIntent(DefaultAppInfo info) {
|
||||||
// By default return null. It's up to subclasses to provide logic.
|
// By default return null. It's up to subclasses to provide logic.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Whether to show the default app label as the title, instead of as the summary. */
|
||||||
* Whether to show the default app label as the title, instead of as the summary.
|
|
||||||
*/
|
|
||||||
protected boolean showLabelAsTitle() {
|
protected boolean showLabelAsTitle() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Whether to show the app summary. */
|
||||||
|
protected boolean showAppSummary() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public Drawable getDefaultAppIcon() {
|
public Drawable getDefaultAppIcon() {
|
||||||
if (!isAvailable()) {
|
if (!isAvailable()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -138,4 +144,15 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable CharSequence getDefaultAppSummary() {
|
||||||
|
if (!isAvailable()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final DefaultAppInfo app = getDefaultAppInfo();
|
||||||
|
if (app != null) {
|
||||||
|
return app.getSummary();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -121,64 +121,6 @@ public class CredentialManagerPreferenceControllerTest {
|
|||||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void verifyHiddenIfAutofillSelectedProvider() {
|
|
||||||
CredentialManagerPreferenceController controller =
|
|
||||||
createControllerWithServices(Collections.emptyList());
|
|
||||||
|
|
||||||
// Set the autofill provider.
|
|
||||||
Settings.Secure.putStringForUser(mContext.getContentResolver(),
|
|
||||||
Settings.Secure.AUTOFILL_SERVICE, "com.example.test/AutofillClass",
|
|
||||||
UserHandle.myUserId());
|
|
||||||
|
|
||||||
// Verify the error cases
|
|
||||||
assertThat(controller.isProviderHiddenBecauseOfAutofill(null)).isFalse();
|
|
||||||
assertThat(controller.isProviderHiddenBecauseOfAutofill("")).isFalse();
|
|
||||||
assertThat(controller.isProviderHiddenBecauseOfAutofill("test")).isFalse();
|
|
||||||
|
|
||||||
// Verify the example.
|
|
||||||
assertThat(controller.isProviderHiddenBecauseOfAutofill("com.example.test")).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void displayPreference_noServices_noPreferencesAdded_useAutofillUri() {
|
|
||||||
Settings.Secure.putStringForUser(
|
|
||||||
mContext.getContentResolver(),
|
|
||||||
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
|
|
||||||
"test",
|
|
||||||
UserHandle.myUserId());
|
|
||||||
|
|
||||||
CredentialManagerPreferenceController controller =
|
|
||||||
createControllerWithServices(Collections.emptyList());
|
|
||||||
controller.displayPreference(mScreen);
|
|
||||||
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
|
||||||
|
|
||||||
Preference pref = mCredentialsPreferenceCategory.getPreference(0);
|
|
||||||
assertThat(pref.getTitle()).isEqualTo("Add service");
|
|
||||||
|
|
||||||
assertThat(controller.getAddServiceUri(mContext)).isEqualTo("test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void displayPreference_noServices_noPreferencesAdded_useCredManUri() {
|
|
||||||
Settings.Secure.putStringForUser(
|
|
||||||
mContext.getContentResolver(),
|
|
||||||
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
|
|
||||||
"test",
|
|
||||||
UserHandle.myUserId());
|
|
||||||
|
|
||||||
CredentialManagerPreferenceController controller =
|
|
||||||
createControllerWithServicesAndAddServiceOverride(
|
|
||||||
Collections.emptyList(), "credman");
|
|
||||||
controller.displayPreference(mScreen);
|
|
||||||
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
|
||||||
|
|
||||||
Preference pref = mCredentialsPreferenceCategory.getPreference(0);
|
|
||||||
assertThat(pref.getTitle()).isEqualTo("Add service");
|
|
||||||
|
|
||||||
assertThat(controller.getAddServiceUri(mContext)).isEqualTo("credman");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void displayPreference_withServices_preferencesAdded() {
|
public void displayPreference_withServices_preferencesAdded() {
|
||||||
CredentialManagerPreferenceController controller =
|
CredentialManagerPreferenceController controller =
|
||||||
|
Reference in New Issue
Block a user