Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd789d56 authored by Haoran Zhang's avatar Haoran Zhang
Browse files

Autofill For All Apps - refactor to have important and not impotant views call...

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

We couldn't change the flag name for denylist because we don't want to suddenly turn down AFAA on droidfood population. So for now we will use the old flag name, but the denylist
would also be applied to important views.

bug: 265186343
Test: atest AutofillForAllAppsTest

Change-Id: I2bd1d1ccd2e939a512297da74106284293685620
parent 4df2f384
Loading
Loading
Loading
Loading
+25 −34
Original line number Diff line number Diff line
@@ -163,7 +163,6 @@ 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;
@@ -10340,24 +10339,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    }
    /**
     * Check whether current activity / package is in denylist.If it's in the denylist,
     * then the views marked as not important for autofill are not eligible for autofill.
     * Check whether current activity / package is in autofill denylist.
     *
     * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in
     * assist structure
     */
    final boolean isActivityDeniedForAutofillForUnimportantView() {
        final AutofillManager afm = getAutofillManager();
        // keep behavior same with denylist feature not enabled
        if (afm == null) return true;
        return afm.isActivityDeniedForAutofillForUnimportantView();
        if (afm == null) return false;
        return afm.isActivityDeniedForAutofill();
    }
    /**
     * Check whether current view matches autofillable heuristics
     *
     * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in
     * assist structure
     */
    final boolean isMatchingAutofillableHeuristics() {
        final AutofillManager afm = getAutofillManager();
        // keep default behavior
        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() {
@@ -10373,39 +10377,26 @@ 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
        // Check whether view is not part of an activity. If it's not, return false.
        if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) {
            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.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
            if (!notifyAugmentedAutofillIfNeeded(afm)){
                return false;
            }
        // If view is important and filter important view flag is turned on, or view is not
        // important and trigger fill request on not important view flag is turned on, then use
        // AutofillManager.isAutofillable() to decide whether view is autofillable instead.
        if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled())
                || (!isImportantForAutofill()
                    && afm.isTriggerFillRequestOnUnimportantViewEnabled())) {
            return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm);
        }
        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 **/
    public boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) {
    private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) {
        final AutofillOptions options = mContext.getAutofillOptions();
        if (options == null || !options.isAugmentedAutofillEnabled(mContext)) {
            return false;
+4 −1
Original line number Diff line number Diff line
@@ -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
     */
+44 −28
Original line number Diff line number Diff line
@@ -685,11 +685,11 @@ public final class AutofillManager {

    // If a package is fully denied, then all views that marked as not
    // 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
    // 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
    private Set<String> mDeniedActivitiySet = new ArraySet<>();
@@ -874,15 +874,15 @@ public final class AutofillManager {

        final String packageName = mContext.getPackageName();

        mIsPackageFullyDeniedForAutofillForUnimportantView =
            isPackageFullyDeniedForAutofillForUnimportantView(denyListString, packageName);
        mIsPackageFullyDeniedForAutofill =
            isPackageFullyDeniedForAutofill(denyListString, packageName);

        if (!mIsPackageFullyDeniedForAutofillForUnimportantView) {
            mIsPackagePartiallyDeniedForAutofillForUnimportantView =
                isPackagePartiallyDeniedForAutofillForUnimportantView(denyListString, packageName);
        if (!mIsPackageFullyDeniedForAutofill) {
            mIsPackagePartiallyDeniedForAutofill =
                isPackagePartiallyDeniedForAutofill(denyListString, packageName);
        }

        if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) {
        if (mIsPackagePartiallyDeniedForAutofill) {
            setDeniedActivitySetWithDenyList(denyListString, packageName);
        }
    }
@@ -896,6 +896,15 @@ public final class AutofillManager {
        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
     *
@@ -904,13 +913,13 @@ public final class AutofillManager {
    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
            Log.d(TAG, "view not autofillable - not passing ime action check");
            return false;
        }
        return true;
    }

    private boolean isPackageFullyDeniedForAutofillForUnimportantView(
    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
@@ -918,7 +927,7 @@ public final class AutofillManager {
        return denyListString.indexOf(packageName + ":;") != -1;
    }

    private boolean isPackagePartiallyDeniedForAutofillForUnimportantView(
    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
@@ -966,17 +975,16 @@ public final class AutofillManager {
    }

    /**
     * Check whether autofill is denied for current activity or package. Used when a view is marked
     * as not important for autofill, if current activity or package is denied, then the view won't
     * trigger fill request.
     * Check whether autofill is denied for current activity or package. If current activity or
     * package is denied, then the view won't trigger fill request.
     *
     * @hide
     */
    public final boolean isActivityDeniedForAutofillForUnimportantView() {
        if (mIsPackageFullyDeniedForAutofillForUnimportantView) {
    public boolean isActivityDeniedForAutofill() {
        if (mIsPackageFullyDeniedForAutofill) {
            return true;
        }
        if (mIsPackagePartiallyDeniedForAutofillForUnimportantView) {
        if (mIsPackagePartiallyDeniedForAutofill) {
            final AutofillClient client = getClient();
            if (client == null) {
                return false;
@@ -990,27 +998,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
     */
    public final boolean isMatchingAutofillableHeuristicsForNotImportantViews(@NonNull View view) {
        if (!mIsTriggerFillRequestOnUnimportantViewEnabled) {
    public boolean isAutofillable(View view) {
        if (isActivityDeniedForAutofill()) {
            Log.d(TAG, "view is not autofillable - activity denied for autofill");
            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)
        // 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 (view instanceof EditText) {
            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
            || view instanceof Spinner
            || view instanceof DatePicker
@@ -1019,10 +1036,9 @@ public final class AutofillManager {
            return true;
        }

        return mShouldEnableAutofillOnAllViewTypes;
        return false;
    }


    /**
     * @hide
     */