Merge "Autofill For All Apps - Add in autofill allowlist" into udc-dev

This commit is contained in:
Haoran Zhang
2023-03-27 22:47:35 +00:00
committed by Android (Google) Code Review
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 = public static final String DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW =
"package_deny_list_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 * 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 = public static final String DEVICE_CONFIG_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES =
"should_enable_autofill_on_all_view_types"; "should_enable_autofill_on_all_view_types";
// END AUTOFILL FOR ALL APPS FLAGS // // END AUTOFILL FOR ALL APPS FLAGS //
@@ -378,6 +388,16 @@ public class AutofillFeatureFlags {
DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW, ""); 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 // START AUTOFILL PCC CLASSIFICATION FUNCTIONS

View File

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