1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.biometrics; 18 19 import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED; 20 21 import android.annotation.CallbackExecutor; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.content.DialogInterface; 26 import android.hardware.biometrics.BiometricPrompt.ButtonInfo; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.util.Log; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 33 import java.util.concurrent.Executor; 34 35 /** 36 * Contains the information of the template of content view with a more options button for 37 * Biometric Prompt. 38 * <p> 39 * This button should be used to provide more options for sign in or other purposes, such as when a 40 * user needs to select between multiple app-specific accounts or profiles that are available for 41 * sign in. 42 * <p> 43 * Apps should avoid using this when possible because it will create additional steps that the user 44 * must navigate through - clicking the more options button will dismiss the prompt, provide the app 45 * an opportunity to ask the user for the correct option, and finally allow the app to decide how to 46 * proceed once selected. 47 * 48 * <p> 49 * Here's how you'd set a <code>PromptContentViewWithMoreOptionsButton</code> on a Biometric 50 * Prompt: 51 * <pre class="prettyprint"> 52 * BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(...) 53 * .setTitle(...) 54 * .setSubTitle(...) 55 * .setContentView(new PromptContentViewWithMoreOptionsButton.Builder() 56 * .setDescription("test description") 57 * .setMoreOptionsButtonListener(executor, listener) 58 * .build()) 59 * .build(); 60 * </pre> 61 */ 62 public final class PromptContentViewWithMoreOptionsButton implements PromptContentViewParcelable { 63 private static final String TAG = "PromptContentViewWithMoreOptionsButton"; 64 @VisibleForTesting 65 static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225; 66 67 private final String mDescription; 68 private DialogInterface.OnClickListener mListener; 69 private ButtonInfo mButtonInfo; 70 PromptContentViewWithMoreOptionsButton( @onNull String description, @NonNull @CallbackExecutor Executor executor, @NonNull DialogInterface.OnClickListener listener)71 private PromptContentViewWithMoreOptionsButton( 72 @NonNull String description, @NonNull @CallbackExecutor Executor executor, 73 @NonNull DialogInterface.OnClickListener listener) { 74 mDescription = description; 75 mListener = listener; 76 mButtonInfo = new ButtonInfo(executor, listener); 77 } 78 PromptContentViewWithMoreOptionsButton(Parcel in)79 private PromptContentViewWithMoreOptionsButton(Parcel in) { 80 mDescription = in.readString(); 81 } 82 83 /** 84 * Gets the description for the content view, as set by 85 * {@link PromptContentViewWithMoreOptionsButton.Builder#setDescription(String)}. 86 * 87 * @return The description for the content view, or null if the content view has no description. 88 */ 89 @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED) 90 @Nullable getDescription()91 public String getDescription() { 92 return mDescription; 93 } 94 95 /** 96 * Gets the click listener for the more options button on the content view, as set by 97 * {@link PromptContentViewWithMoreOptionsButton.Builder#setMoreOptionsButtonListener(Executor, 98 * DialogInterface.OnClickListener)}. 99 * 100 * @return The click listener for the more options button on the content view. 101 */ 102 @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED) 103 @NonNull getMoreOptionsButtonListener()104 public DialogInterface.OnClickListener getMoreOptionsButtonListener() { 105 return mListener; 106 } 107 getButtonInfo()108 ButtonInfo getButtonInfo() { 109 return mButtonInfo; 110 } 111 112 @Override describeContents()113 public int describeContents() { 114 return 0; 115 } 116 117 @Override writeToParcel(@onNull Parcel dest, int flags)118 public void writeToParcel(@NonNull Parcel dest, int flags) { 119 dest.writeString(mDescription); 120 } 121 122 /** 123 * @see Parcelable.Creator 124 */ 125 @NonNull 126 public static final Creator<PromptContentViewWithMoreOptionsButton> CREATOR = new Creator<>() { 127 @Override 128 public PromptContentViewWithMoreOptionsButton createFromParcel(Parcel in) { 129 return new PromptContentViewWithMoreOptionsButton(in); 130 } 131 132 @Override 133 public PromptContentViewWithMoreOptionsButton[] newArray(int size) { 134 return new PromptContentViewWithMoreOptionsButton[size]; 135 } 136 }; 137 138 /** 139 * A builder that collects arguments to be shown on the content view with more options button. 140 */ 141 public static final class Builder { 142 private String mDescription; 143 private Executor mExecutor; 144 private DialogInterface.OnClickListener mListener; 145 146 /** 147 * Optional: Sets a description that will be shown on the content view. 148 * 149 * @param description The description to display. 150 * @return This builder. 151 */ 152 @NonNull 153 @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED) setDescription(@onNull String description)154 public Builder setDescription(@NonNull String description) { 155 if (description.length() > MAX_DESCRIPTION_CHARACTER_NUMBER) { 156 Log.w(TAG, "The character number of description exceeds " 157 + MAX_DESCRIPTION_CHARACTER_NUMBER); 158 } 159 mDescription = description; 160 return this; 161 } 162 163 /** 164 * Required: Sets the executor and click listener for the more options button on the 165 * prompt content. 166 * 167 * @param executor Executor that will be used to run the on click callback. 168 * @param listener Listener containing a callback to be run when the button is pressed. 169 * @return This builder. 170 */ 171 @NonNull 172 @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED) setMoreOptionsButtonListener(@onNull @allbackExecutor Executor executor, @NonNull DialogInterface.OnClickListener listener)173 public Builder setMoreOptionsButtonListener(@NonNull @CallbackExecutor Executor executor, 174 @NonNull DialogInterface.OnClickListener listener) { 175 mExecutor = executor; 176 mListener = listener; 177 return this; 178 } 179 180 181 /** 182 * Creates a {@link PromptContentViewWithMoreOptionsButton}. 183 * 184 * @return An instance of {@link PromptContentViewWithMoreOptionsButton}. 185 * @throws IllegalArgumentException If the executor of more options button is null, or the 186 * listener of more options button is null. 187 */ 188 @NonNull 189 @RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED) build()190 public PromptContentViewWithMoreOptionsButton build() { 191 if (mExecutor == null) { 192 throw new IllegalArgumentException( 193 "The executor for the listener of more options button on prompt content " 194 + "must be set and non-null if " 195 + "PromptContentViewWithMoreOptionsButton is used."); 196 } 197 if (mListener == null) { 198 throw new IllegalArgumentException( 199 "The listener of more options button on prompt content must be set and " 200 + "non-null if PromptContentViewWithMoreOptionsButton is used."); 201 } 202 return new PromptContentViewWithMoreOptionsButton(mDescription, mExecutor, mListener); 203 } 204 } 205 } 206