Loading core/java/android/view/View.java +28 −6 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ import android.view.translation.ViewTranslationCallback; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.widget.Checkable; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import android.window.OnBackInvokedDispatcher; Loading Loading @@ -10356,7 +10357,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final AutofillManager afm = getAutofillManager(); // keep default behavior if (afm == null) return false; return afm.isMatchingAutofillableHeuristics(this); return afm.isMatchingAutofillableHeuristicsForNotImportantViews(this); } private boolean isAutofillable() { Loading @@ -10372,26 +10373,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } // Experiment imeAction heuristic on important views. If the important view doesn't pass // heuristic check, also check augmented autofill in case augmented autofill is enabled // for the activity // TODO: refactor to have both important views and not important views use the same // heuristic check if (isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled() && this instanceof EditText && !afm.isPassingImeActionCheck((EditText) this) && !notifyAugmentedAutofillIfNeeded(afm)) { // TODO: add a log to indicate what has filtered out the view return false; } if (!isImportantForAutofill()) { // If view matches heuristics and is not denied, it will be treated same as view that's // important for autofill if (afm.isMatchingAutofillableHeuristics(this) if (afm.isMatchingAutofillableHeuristicsForNotImportantViews(this) && !afm.isActivityDeniedForAutofillForUnimportantView()) { return getAutofillViewId() > LAST_APP_AUTOFILL_ID; } // View is not important for "regular" autofill, so we must check if Augmented Autofill // is enabled for the activity final AutofillOptions options = mContext.getAutofillOptions(); if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { if (!notifyAugmentedAutofillIfNeeded(afm)){ return false; } afm.notifyViewEnteredForAugmentedAutofill(this); } return getAutofillViewId() > LAST_APP_AUTOFILL_ID; } /** @hide **/ public boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { final AutofillOptions options = mContext.getAutofillOptions(); if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { return false; } afm.notifyViewEnteredForAugmentedAutofill(this); return true; } /** @hide */ public boolean canNotifyAutofillEnterExitEvent() { return isAutofillable() && isAttachedToWindow(); core/java/android/view/autofill/AutofillFeatureFlags.java +38 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,14 @@ public class AutofillFeatureFlags { public static final String DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_UNIMPORTANT_VIEW = "trigger_fill_request_on_unimportant_view"; /** * Whether to apply heuristic check on important views. * * @hide */ public static final String DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_FILTERED_IMPORTANT_VIEWS = "trigger_fill_request_on_filtered_important_views"; /** * Continas imeAction ids that is irrelevant for autofill. For example, ime_action_search. We * use this to avoid trigger fill request on unimportant views. Loading @@ -167,6 +175,14 @@ public class AutofillFeatureFlags { @SuppressLint("IntentName") public static final String DEVICE_CONFIG_NON_AUTOFILLABLE_IME_ACTION_IDS = "non_autofillable_ime_action_ids"; /** * Whether to enable autofill on all view types (not just checkbox, spinner, datepicker etc...) * * @hide */ 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 @@ -314,6 +330,28 @@ public class AutofillFeatureFlags { DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_UNIMPORTANT_VIEW, false); } /** * Whether to apply heuristic check on important views before triggering fill request * * @hide */ public static boolean isTriggerFillRequestOnFilteredImportantViewsEnabled() { return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_AUTOFILL, DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_FILTERED_IMPORTANT_VIEWS, false); } /** * Whether to enable autofill on all view types. * * @hide */ public static boolean shouldEnableAutofillOnAllViewTypes(){ return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_AUTOFILL, DEVICE_CONFIG_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES, false); } /** * Get the non-autofillable ime actions from flag. This will be used in filtering * condition to trigger fill request. Loading core/java/android/view/autofill/AutofillManager.java +57 −13 Original line number Diff line number Diff line Loading @@ -674,6 +674,12 @@ public final class AutofillManager { // Indicate whether trigger fill request on unimportant views is enabled private boolean mIsTriggerFillRequestOnUnimportantViewEnabled = false; // Indicate whether to apply heuristic check on important views before trigger fill request private boolean mIsTriggerFillRequestOnFilteredImportantViewsEnabled; // Indicate whether to enable autofill for all view types private boolean mShouldEnableAutofillOnAllViewTypes; // A set containing all non-autofillable ime actions passed by flag private Set<String> mNonAutofillableImeActionIdSet = new ArraySet<>(); Loading Loading @@ -855,6 +861,12 @@ public final class AutofillManager { mIsTriggerFillRequestOnUnimportantViewEnabled = AutofillFeatureFlags.isTriggerFillRequestOnUnimportantViewEnabled(); mIsTriggerFillRequestOnFilteredImportantViewsEnabled = AutofillFeatureFlags.isTriggerFillRequestOnFilteredImportantViewsEnabled(); mShouldEnableAutofillOnAllViewTypes = AutofillFeatureFlags.shouldEnableAutofillOnAllViewTypes(); mNonAutofillableImeActionIdSet = AutofillFeatureFlags.getNonAutofillableImeActionIdSetFromFlag(); Loading @@ -865,14 +877,39 @@ public final class AutofillManager { mIsPackageFullyDeniedForAutofillForUnimportantView = isPackageFullyDeniedForAutofillForUnimportantView(denyListString, packageName); if (!mIsPackageFullyDeniedForAutofillForUnimportantView) { mIsPackagePartiallyDeniedForAutofillForUnimportantView = isPackagePartiallyDeniedForAutofillForUnimportantView(denyListString, packageName); } if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) { setDeniedActivitySetWithDenyList(denyListString, packageName); } } /** * Whether to apply heuristic check on important views before triggering fill request * * @hide */ public boolean isTriggerFillRequestOnFilteredImportantViewsEnabled() { return mIsTriggerFillRequestOnFilteredImportantViewsEnabled; } /** * Whether view passes the imeAction check * * @hide */ public boolean isPassingImeActionCheck(EditText editText) { final int actionId = editText.getImeOptions(); if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { // TODO: add a log to indicate what has filtered out the view return false; } return true; } private boolean isPackageFullyDeniedForAutofillForUnimportantView( @NonNull String denyListString, @NonNull String packageName) { // If "PackageName:;" is in the string, then it means the package name is in denylist Loading Loading @@ -957,17 +994,23 @@ public final class AutofillManager { * * @hide */ public final boolean isMatchingAutofillableHeuristics(@NonNull View view) { public final boolean isMatchingAutofillableHeuristicsForNotImportantViews(@NonNull View view) { if (!mIsTriggerFillRequestOnUnimportantViewEnabled) { return false; } // TODO: remove the autofill type check when this function is applied on both important and // not important views. // This check is needed here because once the view type check is lifted, addiditional // unimportant views will be added to the assist structure which may cuase system health // regression (viewGroup#populateChidlrenForAutofill() calls this function to decide whether // to include child view) if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false; if (view instanceof EditText) { final int actionId = ((EditText) view).getImeOptions(); if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { return false; } return true; return isPassingImeActionCheck((EditText) view); } if (view instanceof CheckBox || view instanceof Spinner || view instanceof DatePicker Loading @@ -975,7 +1018,8 @@ public final class AutofillManager { || view instanceof RadioGroup) { return true; } return false; return mShouldEnableAutofillOnAllViewTypes; } Loading Loading
core/java/android/view/View.java +28 −6 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ import android.view.translation.ViewTranslationCallback; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.widget.Checkable; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import android.window.OnBackInvokedDispatcher; Loading Loading @@ -10356,7 +10357,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final AutofillManager afm = getAutofillManager(); // keep default behavior if (afm == null) return false; return afm.isMatchingAutofillableHeuristics(this); return afm.isMatchingAutofillableHeuristicsForNotImportantViews(this); } private boolean isAutofillable() { Loading @@ -10372,26 +10373,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } // Experiment imeAction heuristic on important views. If the important view doesn't pass // heuristic check, also check augmented autofill in case augmented autofill is enabled // for the activity // TODO: refactor to have both important views and not important views use the same // heuristic check if (isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled() && this instanceof EditText && !afm.isPassingImeActionCheck((EditText) this) && !notifyAugmentedAutofillIfNeeded(afm)) { // TODO: add a log to indicate what has filtered out the view return false; } if (!isImportantForAutofill()) { // If view matches heuristics and is not denied, it will be treated same as view that's // important for autofill if (afm.isMatchingAutofillableHeuristics(this) if (afm.isMatchingAutofillableHeuristicsForNotImportantViews(this) && !afm.isActivityDeniedForAutofillForUnimportantView()) { return getAutofillViewId() > LAST_APP_AUTOFILL_ID; } // View is not important for "regular" autofill, so we must check if Augmented Autofill // is enabled for the activity final AutofillOptions options = mContext.getAutofillOptions(); if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { if (!notifyAugmentedAutofillIfNeeded(afm)){ return false; } afm.notifyViewEnteredForAugmentedAutofill(this); } return getAutofillViewId() > LAST_APP_AUTOFILL_ID; } /** @hide **/ public boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { final AutofillOptions options = mContext.getAutofillOptions(); if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { return false; } afm.notifyViewEnteredForAugmentedAutofill(this); return true; } /** @hide */ public boolean canNotifyAutofillEnterExitEvent() { return isAutofillable() && isAttachedToWindow();
core/java/android/view/autofill/AutofillFeatureFlags.java +38 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,14 @@ public class AutofillFeatureFlags { public static final String DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_UNIMPORTANT_VIEW = "trigger_fill_request_on_unimportant_view"; /** * Whether to apply heuristic check on important views. * * @hide */ public static final String DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_FILTERED_IMPORTANT_VIEWS = "trigger_fill_request_on_filtered_important_views"; /** * Continas imeAction ids that is irrelevant for autofill. For example, ime_action_search. We * use this to avoid trigger fill request on unimportant views. Loading @@ -167,6 +175,14 @@ public class AutofillFeatureFlags { @SuppressLint("IntentName") public static final String DEVICE_CONFIG_NON_AUTOFILLABLE_IME_ACTION_IDS = "non_autofillable_ime_action_ids"; /** * Whether to enable autofill on all view types (not just checkbox, spinner, datepicker etc...) * * @hide */ 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 @@ -314,6 +330,28 @@ public class AutofillFeatureFlags { DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_UNIMPORTANT_VIEW, false); } /** * Whether to apply heuristic check on important views before triggering fill request * * @hide */ public static boolean isTriggerFillRequestOnFilteredImportantViewsEnabled() { return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_AUTOFILL, DEVICE_CONFIG_TRIGGER_FILL_REQUEST_ON_FILTERED_IMPORTANT_VIEWS, false); } /** * Whether to enable autofill on all view types. * * @hide */ public static boolean shouldEnableAutofillOnAllViewTypes(){ return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_AUTOFILL, DEVICE_CONFIG_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES, false); } /** * Get the non-autofillable ime actions from flag. This will be used in filtering * condition to trigger fill request. Loading
core/java/android/view/autofill/AutofillManager.java +57 −13 Original line number Diff line number Diff line Loading @@ -674,6 +674,12 @@ public final class AutofillManager { // Indicate whether trigger fill request on unimportant views is enabled private boolean mIsTriggerFillRequestOnUnimportantViewEnabled = false; // Indicate whether to apply heuristic check on important views before trigger fill request private boolean mIsTriggerFillRequestOnFilteredImportantViewsEnabled; // Indicate whether to enable autofill for all view types private boolean mShouldEnableAutofillOnAllViewTypes; // A set containing all non-autofillable ime actions passed by flag private Set<String> mNonAutofillableImeActionIdSet = new ArraySet<>(); Loading Loading @@ -855,6 +861,12 @@ public final class AutofillManager { mIsTriggerFillRequestOnUnimportantViewEnabled = AutofillFeatureFlags.isTriggerFillRequestOnUnimportantViewEnabled(); mIsTriggerFillRequestOnFilteredImportantViewsEnabled = AutofillFeatureFlags.isTriggerFillRequestOnFilteredImportantViewsEnabled(); mShouldEnableAutofillOnAllViewTypes = AutofillFeatureFlags.shouldEnableAutofillOnAllViewTypes(); mNonAutofillableImeActionIdSet = AutofillFeatureFlags.getNonAutofillableImeActionIdSetFromFlag(); Loading @@ -865,14 +877,39 @@ public final class AutofillManager { mIsPackageFullyDeniedForAutofillForUnimportantView = isPackageFullyDeniedForAutofillForUnimportantView(denyListString, packageName); if (!mIsPackageFullyDeniedForAutofillForUnimportantView) { mIsPackagePartiallyDeniedForAutofillForUnimportantView = isPackagePartiallyDeniedForAutofillForUnimportantView(denyListString, packageName); } if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) { setDeniedActivitySetWithDenyList(denyListString, packageName); } } /** * Whether to apply heuristic check on important views before triggering fill request * * @hide */ public boolean isTriggerFillRequestOnFilteredImportantViewsEnabled() { return mIsTriggerFillRequestOnFilteredImportantViewsEnabled; } /** * Whether view passes the imeAction check * * @hide */ public boolean isPassingImeActionCheck(EditText editText) { final int actionId = editText.getImeOptions(); if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { // TODO: add a log to indicate what has filtered out the view return false; } return true; } private boolean isPackageFullyDeniedForAutofillForUnimportantView( @NonNull String denyListString, @NonNull String packageName) { // If "PackageName:;" is in the string, then it means the package name is in denylist Loading Loading @@ -957,17 +994,23 @@ public final class AutofillManager { * * @hide */ public final boolean isMatchingAutofillableHeuristics(@NonNull View view) { public final boolean isMatchingAutofillableHeuristicsForNotImportantViews(@NonNull View view) { if (!mIsTriggerFillRequestOnUnimportantViewEnabled) { return false; } // TODO: remove the autofill type check when this function is applied on both important and // not important views. // This check is needed here because once the view type check is lifted, addiditional // unimportant views will be added to the assist structure which may cuase system health // regression (viewGroup#populateChidlrenForAutofill() calls this function to decide whether // to include child view) if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false; if (view instanceof EditText) { final int actionId = ((EditText) view).getImeOptions(); if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { return false; } return true; return isPassingImeActionCheck((EditText) view); } if (view instanceof CheckBox || view instanceof Spinner || view instanceof DatePicker Loading @@ -975,7 +1018,8 @@ public final class AutofillManager { || view instanceof RadioGroup) { return true; } return false; return mShouldEnableAutofillOnAllViewTypes; } Loading