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

Commit b47dd707 authored by Simranjit Kohli's avatar Simranjit Kohli Committed by Android (Google) Code Review
Browse files

Merge "[Autofill CredMan]: Autofill changes for CredMan integration"

parents 8eb891d6 19d62c9a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -51432,6 +51432,7 @@ package android.view {
    method public boolean isAutoHandwritingEnabled();
    method public boolean isClickable();
    method public boolean isContextClickable();
    method public boolean isCredential();
    method public boolean isDirty();
    method @Deprecated public boolean isDrawingCacheEnabled();
    method public boolean isDuplicateParentStateEnabled();
@@ -51665,6 +51666,7 @@ package android.view {
    method public void setImportantForAccessibility(int);
    method public void setImportantForAutofill(int);
    method public void setImportantForContentCapture(int);
    method public void setIsCredential(boolean);
    method public void setKeepScreenOn(boolean);
    method public void setKeyboardNavigationCluster(boolean);
    method public void setLabelFor(@IdRes int);
+8 −3
Original line number Diff line number Diff line
@@ -3206,6 +3206,14 @@ package android.view.animation {

package android.view.autofill {

  public class AutofillFeatureFlags {
    field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
    field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED = "autofill_credential_manager_enabled";
    field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS = "autofill_credential_manager_ignore_views";
    field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
    field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
  }

  public final class AutofillId implements android.os.Parcelable {
    ctor public AutofillId(int);
    ctor public AutofillId(@NonNull android.view.autofill.AutofillId, int);
@@ -3217,9 +3225,6 @@ package android.view.autofill {
  }

  public final class AutofillManager {
    field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
    field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
    field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
    field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
    field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
    field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
+48 −0
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ import android.view.accessibility.AccessibilityWindowInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import android.view.autofill.AutofillFeatureFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -3662,6 +3663,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * Indicates that the view enables auto handwriting initiation.
     */
    private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000;
    /**
     * Indicates that the view is important for Credential Manager.
     */
    private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000;
    /* End of masks for mPrivateFlags4 */
    /** @hide */
@@ -6130,6 +6137,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                        setImportantForContentCapture(a.getInt(attr,
                                IMPORTANT_FOR_CONTENT_CAPTURE_AUTO));
                    }
                    break;
                case R.styleable.View_isCredential:
                    if (a.peekValue(attr) != null) {
                        setIsCredential(a.getBoolean(attr, false));
                    }
                    break;
                case R.styleable.View_defaultFocusHighlightEnabled:
                    if (a.peekValue(attr) != null) {
                        setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
@@ -10234,6 +10247,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private boolean isAutofillable() {
        if (getAutofillType() == AUTOFILL_TYPE_NONE) return false;
        // Disable triggering autofill if the view is integrated with CredentialManager.
        if (AutofillFeatureFlags.shouldIgnoreCredentialViews()
                && isCredential()) return false;
        if (!isImportantForAutofill()) {
            // View is not important for "regular" autofill, so we must check if Augmented Autofill
            // is enabled for the activity
@@ -31860,6 +31877,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
    }
    /**
     * Gets the mode for determining whether this view is a credential.
     *
     * <p>See {@link #isCredential()}.
     *
     * @param isCredential Whether the view is a credential.
     *
     * @attr ref android.R.styleable#View_isCredential
     */
    public void setIsCredential(boolean isCredential) {
        if (isCredential) {
            mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER;
        } else {
            mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER;
        }
    }
    /**
     * Gets the mode for determining whether this view is a credential.
     *
     * <p>See {@link #setIsCredential(boolean)}.
     *
     * @return false by default, or value passed to {@link #setIsCredential(boolean)}.
     *
     * @attr ref android.R.styleable#View_isCredential
     */
    public boolean isCredential() {
        return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER)
                == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER);
    }
    /**
     * Set whether this view enables automatic handwriting initiation.
     *
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.autofill;

import android.annotation.TestApi;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.view.View;

import com.android.internal.util.ArrayUtils;

/**
 * Feature flags associated with autofill.
 * @hide
 */
@TestApi
public class AutofillFeatureFlags {

    /**
     * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
     * are available.
     */
    public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
            "smart_suggestion_supported_modes";

    /**
     * Sets how long (in ms) the augmented autofill service is bound while idle.
     *
     * <p>Use {@code 0} to keep it permanently bound.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
            "augmented_service_idle_unbind_timeout";

    /**
     * Sets how long (in ms) the augmented autofill service request is killed if not replied.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
            "augmented_service_request_timeout";

    /**
     * Sets allowed list for the autofill compatibility mode.
     *
     * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
     * package and an optional list of url bar resource ids (the list is delimited by
     * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
     *
     * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
     * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
     * have 2 ids {@code url_foo} and {@code url_bas}) would be
     * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
     */
    public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
            "compat_mode_allowed_packages";

    /**
     * Indicates Fill dialog feature enabled or not.
     */
    public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED =
            "autofill_dialog_enabled";

    /**
     * Sets the autofill hints allowed list for the fields that can trigger the fill dialog
     * feature at Activity starting.
     *
     * The list of autofill hints is {@code ":"} colon delimited.
     *
     *  <p>For example, a list with 3 hints {@code password}, {@code phone}, and
     * { @code emailAddress}, would be {@code password:phone:emailAddress}
     *
     * Note: By default the password field is enabled even there is no password hint in the list
     *
     * @see View#setAutofillHints(String...)
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS =
            "autofill_dialog_hints";

    // START CREDENTIAL MANAGER FLAGS //

    /**
     * Indicates whether credential manager tagged views should be ignored from autofill structures.
     * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
     */
    public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS =
            "autofill_credential_manager_ignore_views";

    /**
     * Indicates CredentialManager feature enabled or not.
     * This is the overall feature flag. Individual behavior of credential manager may be controlled
     * via a different flag, but gated by this flag.
     */
    public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED =
            "autofill_credential_manager_enabled";

    /**
     * Indicates whether credential manager tagged views should suppress fill dialog.
     * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG =
            "autofill_credential_manager_suppress_fill_dialog";



    /**
     * Indicates whether credential manager tagged views should suppress save dialog.
     * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG =
            "autofill_credential_manager_suppress_save_dialog";
    // END CREDENTIAL MANAGER FLAGS //

    /**
     * Sets a value of delay time to show up the inline tooltip view.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY =
            "autofill_inline_tooltip_first_show_delay";

    private static final String DIALOG_HINTS_DELIMITER = ":";

    private static final boolean DEFAULT_HAS_FILL_DIALOG_UI_FEATURE = false;
    private static final String DEFAULT_FILL_DIALOG_ENABLED_HINTS = "";

    // CREDENTIAL MANAGER DEFAULTS
    // Credential manager is enabled by default so as to allow testing by app developers
    private static final boolean DEFAULT_CREDENTIAL_MANAGER_ENABLED = true;
    private static final boolean DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS = true;
    private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG = false;
    private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG = false;
    // END CREDENTIAL MANAGER DEFAULTS

    private AutofillFeatureFlags() {};

    /**
     * Whether the fill dialog feature is enabled or not
     *
     * @hide
     */
    public static boolean isFillDialogEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED,
                DEFAULT_HAS_FILL_DIALOG_UI_FEATURE);
    }

    /**
     * Gets fill dialog enabled hints.
     *
     * @hide
     */
    public static String[] getFillDialogEnabledHints() {
        final String dialogHints = DeviceConfig.getString(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
                DEFAULT_FILL_DIALOG_ENABLED_HINTS);
        if (TextUtils.isEmpty(dialogHints)) {
            return new String[0];
        }

        return ArrayUtils.filter(dialogHints.split(DIALOG_HINTS_DELIMITER), String[]::new,
                (str) -> !TextUtils.isEmpty(str));
    }

    /**
     * Whether the Credential Manager feature is enabled or not
     *
     * @hide
     */
    public static boolean isCredentialManagerEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED,
                DEFAULT_CREDENTIAL_MANAGER_ENABLED);
    }

    /**
     * Whether credential manager tagged views should be ignored for autofill structure.
     *
     * @hide
     */
    public static boolean shouldIgnoreCredentialViews() {
        return isCredentialManagerEnabled()
                && DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS,
                DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS);
    }

    /**
     * Whether credential manager tagged views should not trigger fill dialog requests.
     *
     * @hide
     */
    public static boolean isFillDialogDisabledForCredentialManager() {
        return isCredentialManagerEnabled()
                && DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG,
                DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG);
    }
}
+20 −109
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.service.autofill.AutofillService;
import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
@@ -450,88 +449,6 @@ public final class AutofillManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface SmartSuggestionMode {}

    /**
     * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
     * are available.
     *
     * @hide
     */
    @TestApi
    public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
            "smart_suggestion_supported_modes";

    /**
     * Sets how long (in ms) the augmented autofill service is bound while idle.
     *
     * <p>Use {@code 0} to keep it permanently bound.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
            "augmented_service_idle_unbind_timeout";

    /**
     * Sets how long (in ms) the augmented autofill service request is killed if not replied.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
            "augmented_service_request_timeout";

    /**
     * Sets allowed list for the autofill compatibility mode.
     *
     * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
     * package and an optional list of url bar resource ids (the list is delimited by
     * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
     *
     * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
     * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
     * have 2 ids {@code url_foo} and {@code url_bas}) would be
     * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
     *
     * @hide
     */
    @TestApi
    public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
            "compat_mode_allowed_packages";

    /**
     * Sets the fill dialog feature enabled or not.
     *
     * @hide
     */
    @TestApi
    public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED =
            "autofill_dialog_enabled";

    /**
     * Sets the autofill hints allowed list for the fields that can trigger the fill dialog
     * feature at Activity starting.
     *
     * The list of autofill hints is {@code ":"} colon delimited.
     *
     * <p>For example, a list with 3 hints {@code password}, {@code phone}, and
     * {@code emailAddress}, would be {@code password:phone:emailAddress}
     *
     * Note: By default the password field is enabled even there is no password hint in the list
     *
     * @see View#setAutofillHints(String...)
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS =
            "autofill_dialog_hints";

    /**
     * Sets a value of delay time to show up the inline tooltip view.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY =
            "autofill_inline_tooltip_first_show_delay";

    private static final String DIALOG_HINTS_DELIMITER = ":";

    /** @hide */
    public static final int RESULT_OK = 0;
    /** @hide */
@@ -634,9 +551,6 @@ public final class AutofillManager {
     */
    public static final int NO_SESSION = Integer.MAX_VALUE;

    private static final boolean HAS_FILL_DIALOG_UI_FEATURE_DEFAULT = false;
    private static final String FILL_DIALOG_ENABLED_DEFAULT_HINTS = "";

    private final IAutoFillManager mService;

    private final Object mLock = new Object();
@@ -891,11 +805,8 @@ public final class AutofillManager {
        mOptions = context.getAutofillOptions();
        mIsFillRequested = new AtomicBoolean(false);

        mIsFillDialogEnabled = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED,
                HAS_FILL_DIALOG_UI_FEATURE_DEFAULT);
        mFillDialogEnabledHints = getFillDialogEnabledHints();
        mIsFillDialogEnabled = AutofillFeatureFlags.isFillDialogEnabled();
        mFillDialogEnabledHints = AutofillFeatureFlags.getFillDialogEnabledHints();
        if (sDebug) {
            Log.d(TAG, "Fill dialog is enabled:" + mIsFillDialogEnabled
                    + ", hints=" + Arrays.toString(mFillDialogEnabledHints));
@@ -907,19 +818,6 @@ public final class AutofillManager {
        }
    }

    private String[] getFillDialogEnabledHints() {
        final String dialogHints = DeviceConfig.getString(
                DeviceConfig.NAMESPACE_AUTOFILL,
                DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
                FILL_DIALOG_ENABLED_DEFAULT_HINTS);
        if (TextUtils.isEmpty(dialogHints)) {
            return new String[0];
        }

        return ArrayUtils.filter(dialogHints.split(DIALOG_HINTS_DELIMITER), String[]::new,
                (str) -> !TextUtils.isEmpty(str));
    }

    /**
     * @hide
     */
@@ -1190,16 +1088,28 @@ public final class AutofillManager {
    }

    /**
     * The {@link #DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or the view have
     * the allowed autofill hints, performs a fill request to know there is any field supported
     * fill dialog.
     * The {@link AutofillFeatureFlags#DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or
     * the view have the allowed autofill hints, performs a fill request to know there is any field
     * supported fill dialog.
     *
     * @hide
     */
    public void notifyViewEnteredForFillDialog(View v) {
        if (sDebug) {
            Log.d(TAG, "notifyViewEnteredForFillDialog:" + v.getAutofillId());
        }
        if (!hasAutofillFeature()) {
            return;
        }
        if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
                && v.isCredential()) {
            if (sDebug) {
                Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
                        + v.getAutofillId().toString());
            }
            return;
        }

        synchronized (mLock) {
            if (mTrackedViews != null) {
                // To support the fill dialog can show for the autofillable Views in
@@ -1227,8 +1137,8 @@ public final class AutofillManager {
            synchronized (mLock) {
                // To match the id of the IME served view, used AutofillId.NO_AUTOFILL_ID on prefill
                // request, because IME will reset the id of IME served view to 0 when activity
                // start and does not focus on any view. If the id of the prefill request is
                // not match to the IME served view's, Autofill will be blocking to wait inline
                // start and does not focus on any view. If the id of the prefill request does
                // not match the IME served view's, Autofill will be blocking to wait inline
                // request from the IME.
                notifyViewEnteredLocked(/* view= */ null, AutofillId.NO_AUTOFILL_ID,
                        /* bounds= */ null,  /* value= */ null, flags);
@@ -4075,6 +3985,7 @@ public final class AutofillManager {
            }
        }

        @Override
        public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
            final AutofillManager afm = mAfm.get();
            if (afm != null) {
Loading