Merge "Autofill For All Apps - refactor to have important and not impotant views call the same isAutofillable() function in AutofillManager" into udc-dev

This commit is contained in:
Haoran Zhang
2023-03-22 23:32:01 +00:00
committed by Android (Google) Code Review
3 changed files with 73 additions and 63 deletions

View File

@@ -163,7 +163,6 @@ import android.view.translation.ViewTranslationCallback;
import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationRequest;
import android.view.translation.ViewTranslationResponse; import android.view.translation.ViewTranslationResponse;
import android.widget.Checkable; import android.widget.Checkable;
import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable; import android.widget.ScrollBarDrawable;
import android.window.OnBackInvokedDispatcher; import android.window.OnBackInvokedDispatcher;
@@ -10347,24 +10346,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} }
/** /**
* Check whether current activity / package is in denylist.If it's in the denylist, * Check whether current activity / package is in autofill denylist.
* then the views marked as not important for autofill are not eligible for autofill. *
* Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in
* assist structure
*/ */
final boolean isActivityDeniedForAutofillForUnimportantView() { final boolean isActivityDeniedForAutofillForUnimportantView() {
final AutofillManager afm = getAutofillManager(); final AutofillManager afm = getAutofillManager();
// keep behavior same with denylist feature not enabled if (afm == null) return false;
if (afm == null) return true; return afm.isActivityDeniedForAutofill();
return afm.isActivityDeniedForAutofillForUnimportantView();
} }
/** /**
* Check whether current view matches autofillable heuristics * Check whether current view matches autofillable heuristics
*
* Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in
* assist structure
*/ */
final boolean isMatchingAutofillableHeuristics() { final boolean isMatchingAutofillableHeuristics() {
final AutofillManager afm = getAutofillManager(); final AutofillManager afm = getAutofillManager();
// keep default behavior
if (afm == null) return false; if (afm == null) return false;
return afm.isMatchingAutofillableHeuristicsForNotImportantViews(this); // check the flag to see if trigger fill request on not important views is enabled
return afm.isTriggerFillRequestOnUnimportantViewEnabled()
? afm.isAutofillable(this) : false;
} }
private boolean isAutofillable() { private boolean isAutofillable() {
@@ -10380,39 +10384,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false; return false;
} }
// Experiment imeAction heuristic on important views. If the important view doesn't pass // Check whether view is not part of an activity. If it's not, return false.
// heuristic check, also check augmented autofill in case augmented autofill is enabled if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) {
// 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; return false;
} }
if (!isImportantForAutofill()) { // If view is important and filter important view flag is turned on, or view is not
// If view matches heuristics and is not denied, it will be treated same as view that's // important and trigger fill request on not important view flag is turned on, then use
// important for autofill // AutofillManager.isAutofillable() to decide whether view is autofillable instead.
if (afm.isMatchingAutofillableHeuristicsForNotImportantViews(this) if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled())
&& !afm.isActivityDeniedForAutofillForUnimportantView()) { || (!isImportantForAutofill()
return getAutofillViewId() > LAST_APP_AUTOFILL_ID; && afm.isTriggerFillRequestOnUnimportantViewEnabled())) {
} return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm);
// View is not important for "regular" autofill, so we must check if Augmented Autofill
// is enabled for the activity
if (!notifyAugmentedAutofillIfNeeded(afm)){
return false;
}
} }
return getAutofillViewId() > LAST_APP_AUTOFILL_ID; // If the previous condition is not met, fall back to the previous way to trigger fill
// request based on autofill importance instead.
return isImportantForAutofill() ? true : notifyAugmentedAutofillIfNeeded(afm);
} }
/** @hide **/ private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) {
public boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) {
final AutofillOptions options = mContext.getAutofillOptions(); final AutofillOptions options = mContext.getAutofillOptions();
if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { if (options == null || !options.isAugmentedAutofillEnabled(mContext)) {
return false; return false;

View File

@@ -365,7 +365,10 @@ public class AutofillFeatureFlags {
} }
/** /**
* Get denylist string from flag * Get denylist string from flag.
*
* Note: This denylist works both on important view and not important views. The flag used here
* is legacy flag which will be replaced with soon.
* *
* @hide * @hide
*/ */

View File

@@ -687,11 +687,11 @@ public final class AutofillManager {
// If a package is fully denied, then all views that marked as not // If a package is fully denied, then all views that marked as not
// important for autofill will not trigger fill request // important for autofill will not trigger fill request
private boolean mIsPackageFullyDeniedForAutofillForUnimportantView = false; private boolean mIsPackageFullyDeniedForAutofill = false;
// If a package is partially denied, autofill manager will check whether // If a package is partially denied, autofill manager will check whether
// current activity is in deny set to decide whether to trigger fill request // current activity is in deny set to decide whether to trigger fill request
private boolean mIsPackagePartiallyDeniedForAutofillForUnimportantView = 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> mDeniedActivitiySet = new ArraySet<>();
@@ -876,15 +876,15 @@ public final class AutofillManager {
final String packageName = mContext.getPackageName(); final String packageName = mContext.getPackageName();
mIsPackageFullyDeniedForAutofillForUnimportantView = mIsPackageFullyDeniedForAutofill =
isPackageFullyDeniedForAutofillForUnimportantView(denyListString, packageName); isPackageFullyDeniedForAutofill(denyListString, packageName);
if (!mIsPackageFullyDeniedForAutofillForUnimportantView) { if (!mIsPackageFullyDeniedForAutofill) {
mIsPackagePartiallyDeniedForAutofillForUnimportantView = mIsPackagePartiallyDeniedForAutofill =
isPackagePartiallyDeniedForAutofillForUnimportantView(denyListString, packageName); isPackagePartiallyDeniedForAutofill(denyListString, packageName);
} }
if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) { if (mIsPackagePartiallyDeniedForAutofill) {
setDeniedActivitySetWithDenyList(denyListString, packageName); setDeniedActivitySetWithDenyList(denyListString, packageName);
} }
} }
@@ -898,6 +898,15 @@ public final class AutofillManager {
return mIsTriggerFillRequestOnFilteredImportantViewsEnabled; return mIsTriggerFillRequestOnFilteredImportantViewsEnabled;
} }
/**
* Whether to trigger fill request on not important views that passes heuristic check
*
* @hide
*/
public boolean isTriggerFillRequestOnUnimportantViewEnabled() {
return mIsTriggerFillRequestOnUnimportantViewEnabled;
}
/** /**
* Whether view passes the imeAction check * Whether view passes the imeAction check
* *
@@ -906,13 +915,13 @@ public final class AutofillManager {
public boolean isPassingImeActionCheck(EditText editText) { public boolean isPassingImeActionCheck(EditText editText) {
final int actionId = editText.getImeOptions(); final int actionId = editText.getImeOptions();
if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) {
// TODO: add a log to indicate what has filtered out the view Log.d(TAG, "view not autofillable - not passing ime action check");
return false; return false;
} }
return true; return true;
} }
private boolean isPackageFullyDeniedForAutofillForUnimportantView( private boolean isPackageFullyDeniedForAutofill(
@NonNull String denyListString, @NonNull String packageName) { @NonNull String denyListString, @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 means the package name is in denylist
// and there are no activities specified under it. That means the package is fully // and there are no activities specified under it. That means the package is fully
@@ -920,7 +929,7 @@ public final class AutofillManager {
return denyListString.indexOf(packageName + ":;") != -1; return denyListString.indexOf(packageName + ":;") != -1;
} }
private boolean isPackagePartiallyDeniedForAutofillForUnimportantView( private boolean isPackagePartiallyDeniedForAutofill(
@NonNull String denyListString, @NonNull String packageName) { @NonNull String denyListString, @NonNull String packageName) {
// This check happens after checking package is not fully denied. If "PackageName:" instead // 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 in denylist, then it means there are specific activities to be denied. So the package
@@ -968,17 +977,16 @@ public final class AutofillManager {
} }
/** /**
* Check whether autofill is denied for current activity or package. Used when a view is marked * Check whether autofill is denied for current activity or package. If current activity or
* as not important for autofill, if current activity or package is denied, then the view won't * package is denied, then the view won't trigger fill request.
* trigger fill request.
* *
* @hide * @hide
*/ */
public final boolean isActivityDeniedForAutofillForUnimportantView() { public boolean isActivityDeniedForAutofill() {
if (mIsPackageFullyDeniedForAutofillForUnimportantView) { if (mIsPackageFullyDeniedForAutofill) {
return true; return true;
} }
if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) { if (mIsPackagePartiallyDeniedForAutofill) {
final AutofillClient client = getClient(); final AutofillClient client = getClient();
if (client == null) { if (client == null) {
return false; return false;
@@ -992,27 +1000,36 @@ public final class AutofillManager {
} }
/** /**
* Check whether view matches autofill-able heuristics * Check heuristics and other rules to determine if view is autofillable
*
* Note: this function should be only called only when autofill for all apps is turned on. The
* calling method needs to check the corresponding flag to make sure that before calling into
* this function.
* *
* @hide * @hide
*/ */
public final boolean isMatchingAutofillableHeuristicsForNotImportantViews(@NonNull View view) { public boolean isAutofillable(View view) {
if (!mIsTriggerFillRequestOnUnimportantViewEnabled) { if (isActivityDeniedForAutofill()) {
Log.d(TAG, "view is not autofillable - activity denied for autofill");
return false; return false;
} }
// TODO: remove the autofill type check when this function is applied on both important and // Duplicate the autofill type check here because ViewGroup will call this function to
// not important views. // decide whether to include view in assist structure.
// This check is needed here because once the view type check is lifted, addiditional // Also keep the autofill type check inside View#IsAutofillable() to serve as an early out
// unimportant views will be added to the assist structure which may cuase system health // or if other functions need to call it.
// regression (viewGroup#populateChidlrenForAutofill() calls this function to decide whether
// to include child view)
if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false; if (view.getAutofillType() == View.AUTOFILL_TYPE_NONE) return false;
if (view instanceof EditText) { if (view instanceof EditText) {
return isPassingImeActionCheck((EditText) view); return isPassingImeActionCheck((EditText) view);
} }
// Skip view type check if view is important for autofill or
// shouldEnableAutofillOnAllViewTypes flag is turned on
if (view.isImportantForAutofill() || mShouldEnableAutofillOnAllViewTypes) {
return true;
}
if (view instanceof CheckBox if (view instanceof CheckBox
|| view instanceof Spinner || view instanceof Spinner
|| view instanceof DatePicker || view instanceof DatePicker
@@ -1021,10 +1038,9 @@ public final class AutofillManager {
return true; return true;
} }
return mShouldEnableAutofillOnAllViewTypes; return false;
} }
/** /**
* @hide * @hide
*/ */