Files
app_Settings/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
Becca Hughes ea03b3e2a0 Add combined provider class that manages new settings UI
Example of how to use: https://paste.googleplex.com/6523798525313024

Test: make
Bug: 278919696
Change-Id: I934a5f6d02b50f8c97bda6d997902a42ff88e26f
2023-05-02 17:37:44 +00:00

263 lines
9.7 KiB
Java

/*
* Copyright (C) 2023 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.applications.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialProviderInfo;
import android.graphics.drawable.Drawable;
import android.service.autofill.AutofillServiceInfo;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Holds combined autofill and credential manager data grouped by package name. Contains backing
* logic for each row in settings.
*/
public final class CombinedProviderInfo {
private final List<CredentialProviderInfo> mCredentialProviderInfos;
private final @Nullable AutofillServiceInfo mAutofillServiceInfo;
private final boolean mIsDefaultAutofillProvider;
private final boolean mIsDefaultCredmanProvider;
/** Constructs an information instance from both autofill and credential provider. */
public CombinedProviderInfo(
@Nullable List<CredentialProviderInfo> cpis,
@Nullable AutofillServiceInfo asi,
boolean isDefaultAutofillProvider,
boolean isDefaultCredmanProvider) {
mCredentialProviderInfos = new ArrayList<>(cpis);
mAutofillServiceInfo = asi;
mIsDefaultAutofillProvider = isDefaultAutofillProvider;
mIsDefaultCredmanProvider = isDefaultCredmanProvider;
}
/** Returns the credential provider info. */
@Nullable
public List<CredentialProviderInfo> getCredentialProviderInfos() {
return mCredentialProviderInfos;
}
/** Returns the autofill provider info. */
@Nullable
public AutofillServiceInfo getAutofillServiceInfo() {
return mAutofillServiceInfo;
}
/** Returns the application info. */
public @Nullable ApplicationInfo getApplicationInfo() {
if (!mCredentialProviderInfos.isEmpty()) {
return mCredentialProviderInfos.get(0).getServiceInfo().applicationInfo;
}
return mAutofillServiceInfo.getServiceInfo().applicationInfo;
}
/** Returns the app icon. */
@Nullable
public Drawable getAppIcon(@NonNull Context context) {
Drawable icon = null;
ServiceInfo brandingService = getBrandingService();
if (brandingService != null) {
icon = brandingService.loadIcon(context.getPackageManager());
}
// If the branding service gave us a icon then use that.
if (icon != null) {
return icon;
}
// Otherwise fallback to the app label and then the package name.
return getApplicationInfo().loadIcon(context.getPackageManager());
}
/** Returns the app name. */
@Nullable
public CharSequence getAppName(@NonNull Context context) {
CharSequence name = "";
ServiceInfo brandingService = getBrandingService();
if (brandingService != null) {
name = brandingService.loadLabel(context.getPackageManager());
}
// If the branding service gave us a name then use that.
if (!TextUtils.isEmpty(name)) {
return name;
}
// Otherwise fallback to the app label and then the package name.
name = getApplicationInfo().loadLabel(context.getPackageManager());
if (TextUtils.isEmpty(name)) {
name = getApplicationInfo().packageName;
}
return name;
}
/** Gets the service to use for branding (name, icons). */
public @Nullable ServiceInfo getBrandingService() {
// If the app has an autofill service then use that.
if (mAutofillServiceInfo != null) {
return mAutofillServiceInfo.getServiceInfo();
}
// If there are no credman providers then stop here.
if (mCredentialProviderInfos.isEmpty()) {
return null;
}
// Build a list of credential providers and sort them by component names
// alphabetically to ensure we are deterministic when picking the provider.
Map<String, ServiceInfo> flattenedNamesToServices = new HashMap<>();
List<String> flattenedNames = new ArrayList<>();
for (CredentialProviderInfo cpi : mCredentialProviderInfos) {
final String flattenedName = cpi.getComponentName().flattenToString();
flattenedNamesToServices.put(flattenedName, cpi.getServiceInfo());
flattenedNames.add(flattenedName);
}
Collections.sort(flattenedNames);
return flattenedNamesToServices.get(flattenedNames.get(0));
}
/** Returns whether the provider is the default autofill provider. */
public boolean isDefaultAutofillProvider() {
return mIsDefaultAutofillProvider;
}
/** Returns whether the provider is the default credman provider. */
public boolean isDefaultCredmanProvider() {
return mIsDefaultCredmanProvider;
}
/** Returns the settings subtitle. */
@Nullable
public String getSettingsSubtitle() {
List<String> subtitles = new ArrayList<>();
for (CredentialProviderInfo cpi : mCredentialProviderInfos) {
// Convert from a CharSequence.
String subtitle = String.valueOf(cpi.getSettingsSubtitle());
if (subtitle != null && !TextUtils.isEmpty(subtitle) && !subtitle.equals("null")) {
subtitles.add(subtitle);
}
}
if (subtitles.size() == 0) {
return "";
}
return String.join(", ", subtitles);
}
/** Returns the autofill component name string. */
@Nullable
public String getAutofillServiceString() {
if (mAutofillServiceInfo != null) {
return mAutofillServiceInfo.getServiceInfo().getComponentName().flattenToString();
}
return null;
}
/** Returns the provider that gets the top spot. */
public static @Nullable CombinedProviderInfo getTopProvider(
List<CombinedProviderInfo> providers) {
// If there is an autofill provider then it should be the
// top app provider.
for (CombinedProviderInfo cpi : providers) {
if (cpi.isDefaultAutofillProvider()) {
return cpi;
}
}
// TODO(280454916): Add logic here.
return null;
}
public static List<CombinedProviderInfo> buildMergedList(
List<AutofillServiceInfo> asiList,
List<CredentialProviderInfo> cpiList,
@Nullable String defaultAutofillProvider) {
ComponentName defaultAutofillProviderComponent =
(defaultAutofillProvider == null)
? null
: ComponentName.unflattenFromString(defaultAutofillProvider);
// Index the autofill providers by package name.
Set<String> packageNames = new HashSet<>();
Map<String, List<AutofillServiceInfo>> autofillServices = new HashMap<>();
for (AutofillServiceInfo asi : asiList) {
final String packageName = asi.getServiceInfo().packageName;
if (!autofillServices.containsKey(packageName)) {
autofillServices.put(packageName, new ArrayList<>());
}
autofillServices.get(packageName).add(asi);
packageNames.add(packageName);
}
// Index the credman providers by package name.
Map<String, List<CredentialProviderInfo>> credmanServices = new HashMap<>();
for (CredentialProviderInfo cpi : cpiList) {
String packageName = cpi.getServiceInfo().packageName;
if (!credmanServices.containsKey(packageName)) {
credmanServices.put(packageName, new ArrayList<>());
}
credmanServices.get(packageName).add(cpi);
packageNames.add(packageName);
}
// Now go through and build the joint datasets.
List<CombinedProviderInfo> cmpi = new ArrayList<>();
for (String packageName : packageNames) {
List<AutofillServiceInfo> asi = autofillServices.get(packageName);
List<CredentialProviderInfo> cpi = credmanServices.get(packageName);
// If there are multiple autofill services then pick the first one.
AutofillServiceInfo selectedAsi = asi.isEmpty() ? null : asi.get(0);
// Check if we are the default autofill provider.
boolean isDefaultAutofillProvider = false;
if (defaultAutofillProviderComponent != null
&& defaultAutofillProviderComponent.getPackageName().equals(packageName)) {
isDefaultAutofillProvider = true;
}
// Check if we have any enabled cred man services.
boolean isDefaultCredmanProvider = false;
if (!cpi.isEmpty()) {
isDefaultCredmanProvider = cpi.get(0).isEnabled();
}
cmpi.add(
new CombinedProviderInfo(
cpi, selectedAsi, isDefaultAutofillProvider, isDefaultCredmanProvider));
}
return cmpi;
}
}