Loading core/java/android/view/autofill/AutofillFeatureFlags.java +20 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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 // Loading Loading @@ -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 Loading core/java/android/view/autofill/AutofillManager.java +97 −41 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } Loading Loading @@ -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)); } /** Loading @@ -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; } } Loading @@ -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); } Loading @@ -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; } Loading Loading
core/java/android/view/autofill/AutofillFeatureFlags.java +20 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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 // Loading Loading @@ -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 Loading
core/java/android/view/autofill/AutofillManager.java +97 −41 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } Loading Loading @@ -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)); } /** Loading @@ -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; } } Loading @@ -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); } Loading @@ -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; } Loading