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

Commit 75373f9a authored by Hao Dong's avatar Hao Dong Committed by Android (Google) Code Review
Browse files

Merge "Add class PromptContentViewWithMoreOptionsButton" into main

parents 09a2f96f 7b75950d
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -19000,6 +19000,21 @@ package android.hardware.biometrics {
  @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public interface PromptContentView {
  }
  @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public final class PromptContentViewWithMoreOptionsButton implements android.os.Parcelable android.hardware.biometrics.PromptContentView {
    method public int describeContents();
    method @Nullable @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED) public String getDescription();
    method @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED) public android.content.DialogInterface.OnClickListener getMoreOptionsButtonListener();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.biometrics.PromptContentViewWithMoreOptionsButton> CREATOR;
  }
  public static final class PromptContentViewWithMoreOptionsButton.Builder {
    ctor public PromptContentViewWithMoreOptionsButton.Builder();
    method @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED) public android.hardware.biometrics.PromptContentViewWithMoreOptionsButton build();
    method @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED) public android.hardware.biometrics.PromptContentViewWithMoreOptionsButton.Builder setDescription(@NonNull String);
    method @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED) public android.hardware.biometrics.PromptContentViewWithMoreOptionsButton.Builder setMoreOptionsButtonListener(@NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
  }
  @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public final class PromptVerticalListContentView implements android.os.Parcelable android.hardware.biometrics.PromptContentView {
    method public int describeContents();
    method @Nullable public String getDescription();
+15 −3
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
    @Retention(RetentionPolicy.SOURCE)
    public @interface DismissedReason {}

    private static class ButtonInfo {
    static class ButtonInfo {
        Executor executor;
        DialogInterface.OnClickListener listener;
        ButtonInfo(Executor ex, DialogInterface.OnClickListener l) {
@@ -150,6 +150,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
    public static class Builder {
        private PromptInfo mPromptInfo;
        private ButtonInfo mNegativeButtonInfo;
        private ButtonInfo mContentViewMoreOptionsButtonInfo;
        private Context mContext;
        private IAuthService mService;

@@ -301,6 +302,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        @NonNull
        public BiometricPrompt.Builder setContentView(@NonNull PromptContentView view) {
            mPromptInfo.setContentView(view);

            if (mPromptInfo.isContentViewMoreOptionsButtonUsed()) {
                mContentViewMoreOptionsButtonInfo =
                        ((PromptContentViewWithMoreOptionsButton) view).getButtonInfo();
            }

            return this;
        }

@@ -619,7 +626,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            }
            mService = (mService == null) ? IAuthService.Stub.asInterface(
                    ServiceManager.getService(Context.AUTH_SERVICE)) : mService;
            return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo, mService);
            return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo,
                    mContentViewMoreOptionsButtonInfo, mService);
        }
    }

@@ -646,6 +654,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
    private final IAuthService mService;
    private final PromptInfo mPromptInfo;
    private final ButtonInfo mNegativeButtonInfo;
    // TODO(b/328843028): add callback onContentViewMoreOptionsButtonClicked() in
    //  IBiometricServiceReceiver.
    private final ButtonInfo mContentViewMoreOptionsButtonInfo;

    private CryptoObject mCryptoObject;
    private Executor mExecutor;
@@ -751,10 +762,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
    private boolean mIsPromptShowing;

    private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo,
            IAuthService service) {
            ButtonInfo contentViewMoreOptionsButtonInfo, IAuthService service) {
        mContext = context;
        mPromptInfo = promptInfo;
        mNegativeButtonInfo = negativeButtonInfo;
        mContentViewMoreOptionsButtonInfo = contentViewMoreOptionsButtonInfo;
        mService = service;
        mIsPromptShowing = false;
    }
+1 −1
Original line number Diff line number Diff line
@@ -26,5 +26,5 @@ import android.os.Parcelable;
 */
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
sealed interface PromptContentViewParcelable extends PromptContentView, Parcelable
        permits PromptVerticalListContentView {
        permits PromptVerticalListContentView, PromptContentViewWithMoreOptionsButton {
}
+198 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.hardware.biometrics;

import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED;
import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.DialogInterface;
import android.hardware.biometrics.BiometricPrompt.ButtonInfo;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.concurrent.Executor;

/**
 * Contains the information of the template of content view with a more options button for Biometric
 * Prompt.
 * This button should be used to provide more options for sign in or other purposes, such as when a
 * user needs to select between multiple app-specific accounts or profiles that are available for
 * sign in. This is not common and apps should avoid using it if there is only one choice available
 * or if the user has already selected the appropriate account to use before invoking
 * BiometricPrompt because it will create additional steps that the user must navigate through.
 * Clicking the more options button will dismiss the prompt, provide the app an opportunity to ask
 * the user for the correct account, &finally allow the app to decide how to proceed once selected.
 * <p>
 * Here's how you'd set a <code>PromptContentViewWithMoreOptionsButton</code> on a Biometric Prompt:
 * <pre class="prettyprint">
 * BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(...)
 *     .setTitle(...)
 *     .setSubTitle(...)
 *     .setContentView(new PromptContentViewWithMoreOptionsButton.Builder()
 *         .setDescription("test description")
 *         .setMoreOptionsButtonListener(executor, listener)
 *         .build())
 *     .build();
 * </pre>
 */
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
public final class PromptContentViewWithMoreOptionsButton implements PromptContentViewParcelable {

    private final String mDescription;
    private DialogInterface.OnClickListener mListener;
    private ButtonInfo mButtonInfo;

    private PromptContentViewWithMoreOptionsButton(
            @NonNull String description, @NonNull @CallbackExecutor Executor executor,
            @NonNull DialogInterface.OnClickListener listener) {
        mDescription = description;
        mListener = listener;
        mButtonInfo = new ButtonInfo(executor, listener);
    }

    private PromptContentViewWithMoreOptionsButton(Parcel in) {
        mDescription = in.readString();
    }

    /**
     * Gets the description for the content view, as set by
     * {@link PromptContentViewWithMoreOptionsButton.Builder#setDescription(String)}.
     *
     * @return The description for the content view, or null if the content view has no description.
     */
    @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
    @Nullable
    public String getDescription() {
        return mDescription;
    }

    /**
     * Gets the click listener for the more options button on the content view, as set by
     * {@link PromptContentViewWithMoreOptionsButton.Builder#setMoreOptionsButtonListener(Executor,
     * DialogInterface.OnClickListener)}.
     *
     * @return The click listener for the more options button on the content view.
     */
    @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
    @NonNull
    public DialogInterface.OnClickListener getMoreOptionsButtonListener() {
        return mListener;
    }

    ButtonInfo getButtonInfo() {
        return mButtonInfo;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(mDescription);
    }

    /**
     * @see Parcelable.Creator
     */
    @NonNull
    public static final Creator<PromptContentViewWithMoreOptionsButton> CREATOR = new Creator<>() {
        @Override
        public PromptContentViewWithMoreOptionsButton createFromParcel(Parcel in) {
            return new PromptContentViewWithMoreOptionsButton(in);
        }

        @Override
        public PromptContentViewWithMoreOptionsButton[] newArray(int size) {
            return new PromptContentViewWithMoreOptionsButton[size];
        }
    };

    public static final class Builder {
        private String mDescription;
        private Executor mExecutor;
        private DialogInterface.OnClickListener mListener;

        /**
         * Optional: Sets a description that will be shown on the content view.  Note that there are
         * limits on the number of characters allowed for description.
         *
         * @param description The description to display.
         * @return This builder.
         */
        @NonNull
        @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
        public Builder setDescription(@NonNull String description) {
            mDescription = description;
            return this;
        }

        /**
         * Required: Sets the executor and click listener for the more options button on the
         * prompt content.
         * This button should be used to provide more options for sign in or other purposes, such
         * as when a user needs to select between multiple app-specific accounts or profiles that
         * are available for sign in. This is not common and apps should avoid using it if there
         * is only one choice available or if the user has already selected the appropriate
         * account to use before invoking BiometricPrompt because it will create additional steps
         * that the user must navigate through. Clicking the more options button will dismiss the
         * prompt, provide the app an opportunity to ask the user for the correct account, &finally
         * allow the app to decide how to proceed once selected.
         *
         * @param executor Executor that will be used to run the on click callback.
         * @param listener Listener containing a callback to be run when the button is pressed.
         * @return This builder.
         */
        @NonNull
        @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
        public Builder setMoreOptionsButtonListener(@NonNull @CallbackExecutor Executor executor,
                @NonNull DialogInterface.OnClickListener listener) {
            if (executor == null) {
                throw new IllegalArgumentException("Executor must not be null");
            }
            if (listener == null) {
                throw new IllegalArgumentException("Listener must not be null");
            }
            mExecutor = executor;
            mListener = listener;
            return this;
        }


        /**
         * Creates a {@link PromptContentViewWithMoreOptionsButton}.
         *
         * @return An instance of {@link PromptContentViewWithMoreOptionsButton}.
         */
        @NonNull
        @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
        public PromptContentViewWithMoreOptionsButton build() {
            if (mListener == null) {
                throw new IllegalArgumentException(
                        "The listener of more options button on prompt content must be set if "
                                + "PromptContentViewWithMoreOptionsButton is used.");
            }
            return new PromptContentViewWithMoreOptionsButton(mDescription, mExecutor, mListener);
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -191,6 +191,15 @@ public class PromptInfo implements Parcelable {
    public boolean shouldUseParentProfileForDeviceCredential() {
        return mUseParentProfileForDeviceCredential;
    }

    /**
     * Returns if the PromptContentViewWithMoreOptionsButton is set.
     */
    public boolean isContentViewMoreOptionsButtonUsed() {
        return Flags.customBiometricPrompt() && mContentView != null
                && mContentView instanceof PromptContentViewWithMoreOptionsButton;
    }

    // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/BiometricPrompt.java)

    // Setters