Autofill For All Apps - Add in autofill allowlist

bug: 265186343
Test: atest AutofillForAllAppsTest#testAddingActivityToAllowlist_ViewWithImeActionGoStillTriggerFillRequest
      atest AutofillForAllAppsTest#testAddingPacakgeToAllowlist_ViewWithImeActionGoStillTriggerFillRequest

Change-Id: I439124fc69b54796f74245b01d6d37c6f4484bfb
This commit is contained in:
Haoran Zhang
2023-03-21 17:19:16 +00:00
parent ab0b751aef
commit fad3000857
2 changed files with 117 additions and 41 deletions

View File

@@ -149,6 +149,15 @@ public class AutofillFeatureFlags {
public static final String DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW =
"package_deny_list_for_unimportant_view";
/**
* Sets the list of activities and packages allowed for autofill. The format is same with
* {@link #DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW}
*
* @hide
*/
public static final String DEVICE_CONFIG_PACKAGE_AND_ACTIVITY_ALLOWLIST_FOR_TRIGGERING_FILL_REQUEST =
"package_and_activity_allowlist_for_triggering_fill_request";
/**
* Whether the heuristics check for view is enabled
*/
@@ -183,6 +192,7 @@ public class AutofillFeatureFlags {
*/
public static final String DEVICE_CONFIG_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES =
"should_enable_autofill_on_all_view_types";
// END AUTOFILL FOR ALL APPS FLAGS //
@@ -378,6 +388,16 @@ public class AutofillFeatureFlags {
DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW, "");
}
/**
* Get autofill allowlist from flag
*
* @hide
*/
public static String getAllowlistStringFromFlag() {
return DeviceConfig.getString(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_PACKAGE_AND_ACTIVITY_ALLOWLIST_FOR_TRIGGERING_FILL_REQUEST, "");
}
// START AUTOFILL PCC CLASSIFICATION FUNCTIONS

View File

@@ -694,7 +694,18 @@ public final class AutofillManager {
private boolean mIsPackagePartiallyDeniedForAutofill = false;
// A deny set read from device config
private Set<String> mDeniedActivitiySet = new ArraySet<>();
private Set<String> mDeniedActivitySet = new ArraySet<>();
// If a package is fully allowed, all views in package will skip the heuristic check
private boolean mIsPackageFullyAllowedForAutofill = false;
// If a package is partially denied, autofill manager will check whether
// current activity is in allowed activity set. If it's allowed activity, then autofill manager
// will skip the heuristic check
private boolean mIsPackagePartiallyAllowedForAutofill = false;
// An allowed activity set read from device config
private Set<String> mAllowedActivitySet = new ArraySet<>();
// Indicates whether called the showAutofillDialog() method.
private boolean mShowAutofillDialogCalled = false;
@@ -873,19 +884,34 @@ public final class AutofillManager {
AutofillFeatureFlags.getNonAutofillableImeActionIdSetFromFlag();
final String denyListString = AutofillFeatureFlags.getDenylistStringFromFlag();
final String allowlistString = AutofillFeatureFlags.getAllowlistStringFromFlag();
final String packageName = mContext.getPackageName();
mIsPackageFullyDeniedForAutofill =
isPackageFullyDeniedForAutofill(denyListString, packageName);
isPackageFullyAllowedOrDeniedForAutofill(denyListString, packageName);
mIsPackageFullyAllowedForAutofill =
isPackageFullyAllowedOrDeniedForAutofill(allowlistString, packageName);
if (!mIsPackageFullyDeniedForAutofill) {
mIsPackagePartiallyDeniedForAutofill =
isPackagePartiallyDeniedForAutofill(denyListString, packageName);
isPackagePartiallyDeniedOrAllowedForAutofill(denyListString, packageName);
}
if (!mIsPackageFullyAllowedForAutofill) {
mIsPackagePartiallyAllowedForAutofill =
isPackagePartiallyDeniedOrAllowedForAutofill(allowlistString, packageName);
}
if (mIsPackagePartiallyDeniedForAutofill) {
setDeniedActivitySetWithDenyList(denyListString, packageName);
mDeniedActivitySet = getDeniedOrAllowedActivitySetFromString(
denyListString, packageName);
}
if (mIsPackagePartiallyAllowedForAutofill) {
mAllowedActivitySet = getDeniedOrAllowedActivitySetFromString(
allowlistString, packageName);
}
}
@@ -921,59 +947,59 @@ public final class AutofillManager {
return true;
}
private boolean isPackageFullyDeniedForAutofill(
@NonNull String denyListString, @NonNull String packageName) {
// If "PackageName:;" is in the string, then it means the package name is in denylist
// and there are no activities specified under it. That means the package is fully
// denied for autofill
return denyListString.indexOf(packageName + ":;") != -1;
private boolean isPackageFullyAllowedOrDeniedForAutofill(
@NonNull String listString, @NonNull String packageName) {
// If "PackageName:;" is in the string, then it the package is fully denied or allowed for
// autofill, depending on which string is passed to this function
return listString.indexOf(packageName + ":;") != -1;
}
private boolean isPackagePartiallyDeniedForAutofill(
@NonNull String denyListString, @NonNull String packageName) {
// This check happens after checking package is not fully denied. If "PackageName:" instead
// is in denylist, then it means there are specific activities to be denied. So the package
// is partially denied for autofill
return denyListString.indexOf(packageName + ":") != -1;
private boolean isPackagePartiallyDeniedOrAllowedForAutofill(
@NonNull String listString, @NonNull String packageName) {
// If "PackageName:" is in string when "PackageName:;" is not, then it means there are
// specific activities to be allowed or denied. So the package is partially allowed or
// denied for autofill.
return listString.indexOf(packageName + ":") != -1;
}
/**
* Get the denied activitiy names under specified package from denylist and set it in field
* mDeniedActivitiySet
* Get the denied or allowed activitiy names under specified package from the list string and
* set it in fields accordingly
*
* If using parameter as the example below, the denied activity set would be set to
* Set{Activity1,Activity2}.
* For example, if the package name is Package1, and the string is
* "Package1:Activity1,Activity2;", then the extracted activity set would be
* {Activity1, Activity2}
*
* @param denyListString Denylist that is got from device config. For example,
* @param listString Denylist that is got from device config. For example,
* "Package1:Activity1,Activity2;Package2:;"
* @param packageName Specify to extract activities under which package.For example,
* "Package1:;"
* @param packageName Specify which package to extract.For example, "Package1"
*
* @return the extracted activity set, For example, {Activity1, Activity2}
*/
private void setDeniedActivitySetWithDenyList(
@NonNull String denyListString, @NonNull String packageName) {
private Set<String> getDeniedOrAllowedActivitySetFromString(
@NonNull String listString, @NonNull String packageName) {
// 1. Get the index of where the Package name starts
final int packageInStringIndex = denyListString.indexOf(packageName + ":");
final int packageInStringIndex = listString.indexOf(packageName + ":");
// 2. Get the ";" index after this index of package
final int firstNextSemicolonIndex = denyListString.indexOf(";", packageInStringIndex);
final int firstNextSemicolonIndex = listString.indexOf(";", packageInStringIndex);
// 3. Get the activity names substring between the indexes
final int activityStringStartIndex = packageInStringIndex + packageName.length() + 1;
if (activityStringStartIndex >= firstNextSemicolonIndex) {
Log.e(TAG, "Failed to get denied activity names from denylist because it's wrongly "
Log.e(TAG, "Failed to get denied activity names from list because it's wrongly "
+ "formatted");
return;
return new ArraySet<>();
}
final String activitySubstring =
denyListString.substring(activityStringStartIndex, firstNextSemicolonIndex);
listString.substring(activityStringStartIndex, firstNextSemicolonIndex);
// 4. Split the activity name substring
final String[] activityStringArray = activitySubstring.split(",");
// 5. Set the denied activity set
mDeniedActivitiySet = new ArraySet<>(Arrays.asList(activityStringArray));
return;
// 5. return the extracted activities in a set
return new ArraySet<>(Arrays.asList(activityStringArray));
}
/**
@@ -992,7 +1018,32 @@ public final class AutofillManager {
return false;
}
final ComponentName clientActivity = client.autofillClientGetComponentName();
if (mDeniedActivitiySet.contains(clientActivity.flattenToShortString())) {
if (mDeniedActivitySet.contains(clientActivity.flattenToShortString())) {
return true;
}
}
return false;
}
/**
* Check whether current activity is allowlisted for autofill.
*
* If it is, the view in current activity will bypass heuristic check when checking whether it's
* autofillable
*
* @hide
*/
public boolean isActivityAllowedForAutofill() {
if (mIsPackageFullyAllowedForAutofill) {
return true;
}
if (mIsPackagePartiallyAllowedForAutofill) {
final AutofillClient client = getClient();
if (client == null) {
return false;
}
final ComponentName clientActivity = client.autofillClientGetComponentName();
if (mAllowedActivitySet.contains(clientActivity.flattenToShortString())) {
return true;
}
}
@@ -1009,17 +1060,22 @@ public final class AutofillManager {
* @hide
*/
public boolean isAutofillable(View view) {
if (isActivityDeniedForAutofill()) {
Log.d(TAG, "view is not autofillable - activity denied for autofill");
return false;
}
// Duplicate the autofill type check here because ViewGroup will call this function to
// decide whether to include view in assist structure.
// Also keep the autofill type check inside View#IsAutofillable() to serve as an early out
// or if other functions need to call it.
if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false;
if (isActivityDeniedForAutofill()) {
Log.d(TAG, "view is not autofillable - activity denied for autofill");
return false;
}
if (isActivityAllowedForAutofill()) {
Log.d(TAG, "view is autofillable - activity allowed for autofill");
return true;
}
if (view instanceof EditText) {
return isPassingImeActionCheck((EditText) view);
}
@@ -1037,7 +1093,7 @@ public final class AutofillManager {
|| view instanceof RadioGroup) {
return true;
}
Log.d(TAG, "view is not autofillable - not important and filtered by view type check");
return false;
}