summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hao Dong <spdonghao@google.com> 2024-03-20 18:37:18 +0000
committer Hao Dong <spdonghao@google.com> 2024-03-22 21:32:03 +0000
commitcf7d9a50e4a49a94af8e22f6836589d7bec9299a (patch)
tree27a59b723651c9417058e9a3802e747943122936
parentfa4bde6d2134572356ff998945cea6a813369aef (diff)
Add char limits and permission enforcement for custom bp.
Flag: ACONFIG android.hardware.biometrics.custom_biometric_prompt DEVELOPMENT Bug: 302735104 Test: atest BiometricPromptLogoTests Test: atest BiometricPromptContentViewTest Change-Id: Id159cde0df2520b4474c216f8d6503558262fc67
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java11
-rw-r--r--core/java/android/hardware/biometrics/PromptContentViewWithMoreOptionsButton.java39
-rw-r--r--core/java/android/hardware/biometrics/PromptInfo.java7
-rw-r--r--core/java/android/hardware/biometrics/PromptVerticalListContentView.java48
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java6
6 files changed, 67 insertions, 46 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 7d61c142fa04..d9614d1acd6b 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -70,6 +70,7 @@ import javax.crypto.Mac;
public class BiometricPrompt implements BiometricAuthenticator, BiometricConstants {
private static final String TAG = "BiometricPrompt";
+ private static final int MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER = 30;
/**
* Error/help message will show for this amount of time.
@@ -222,11 +223,19 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
*
* @param logoDescription The logo description text that will be shown on the prompt.
* @return This builder.
+ * @throws IllegalStateException If logo description is null or exceeds certain character
+ * limit.
*/
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
@NonNull
public BiometricPrompt.Builder setLogoDescription(@NonNull String logoDescription) {
+ if (logoDescription == null
+ || logoDescription.length() > MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER) {
+ throw new IllegalStateException(
+ "Logo description passed in can not be null or exceed "
+ + MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER + " character number.");
+ }
mPromptInfo.setLogoDescription(logoDescription);
return this;
}
@@ -814,7 +823,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
/**
* Gets the logo description for the prompt, as set by
- * {@link Builder#setDescription(CharSequence)}.
+ * {@link Builder#setLogoDescription(String)}.
* Currently for system applications use only.
*
* @return The logo description of the prompt, or null if the prompt has no logo description
diff --git a/core/java/android/hardware/biometrics/PromptContentViewWithMoreOptionsButton.java b/core/java/android/hardware/biometrics/PromptContentViewWithMoreOptionsButton.java
index 9ebfa8f4301d..853d86cf94dc 100644
--- a/core/java/android/hardware/biometrics/PromptContentViewWithMoreOptionsButton.java
+++ b/core/java/android/hardware/biometrics/PromptContentViewWithMoreOptionsButton.java
@@ -40,9 +40,12 @@ import java.util.concurrent.Executor;
* 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.
+ * the user for the correct account, and 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:
+ * Here's how you'd set a <code>PromptContentViewWithMoreOptionsButton</code> on a Biometric
+ * Prompt:
* <pre class="prettyprint">
* BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(...)
* .setTitle(...)
@@ -56,6 +59,7 @@ import java.util.concurrent.Executor;
*/
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
public final class PromptContentViewWithMoreOptionsButton implements PromptContentViewParcelable {
+ private static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225;
private final String mDescription;
private DialogInterface.OnClickListener mListener;
@@ -139,10 +143,15 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
*
* @param description The description to display.
* @return This builder.
+ * @throws IllegalArgumentException If description exceeds certain character limit.
*/
@NonNull
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
public Builder setDescription(@NonNull String description) {
+ if (description.length() > MAX_DESCRIPTION_CHARACTER_NUMBER) {
+ throw new IllegalStateException("The character number of description exceeds "
+ + MAX_DESCRIPTION_CHARACTER_NUMBER);
+ }
mDescription = description;
return this;
}
@@ -150,14 +159,6 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
/**
* 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.
@@ -167,12 +168,6 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
@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;
@@ -183,15 +178,23 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
* Creates a {@link PromptContentViewWithMoreOptionsButton}.
*
* @return An instance of {@link PromptContentViewWithMoreOptionsButton}.
+ * @throws IllegalArgumentException If the executor of more options button is null, or the
+ * listener of more options button is null.
*/
@NonNull
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
public PromptContentViewWithMoreOptionsButton build() {
- if (mListener == null) {
+ if (mExecutor == null) {
throw new IllegalArgumentException(
- "The listener of more options button on prompt content must be set if "
+ "The executor for the listener of more options button on prompt content "
+ + "must be set and non-null if "
+ "PromptContentViewWithMoreOptionsButton is used.");
}
+ if (mListener == null) {
+ throw new IllegalArgumentException(
+ "The listener of more options button on prompt content must be set and "
+ + "non-null if PromptContentViewWithMoreOptionsButton is used.");
+ }
return new PromptContentViewWithMoreOptionsButton(mDescription, mExecutor, mListener);
}
}
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 814321319e2f..18b75c9b8f8f 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -173,14 +173,19 @@ public class PromptInfo implements Parcelable {
/**
* Returns whether SET_BIOMETRIC_DIALOG_ADVANCED is contained.
+ *
+ * Currently, logo res, logo bitmap, logo description, PromptContentViewWithMoreOptions needs
+ * this permission.
*/
- public boolean containsSetLogoApiConfigurations() {
+ public boolean containsAdvancedApiConfigurations() {
if (mLogoRes != -1) {
return true;
} else if (mLogoBitmap != null) {
return true;
} else if (mLogoDescription != null) {
return true;
+ } else if (mContentView != null && isContentViewMoreOptionsButtonUsed()) {
+ return true;
}
return false;
}
diff --git a/core/java/android/hardware/biometrics/PromptVerticalListContentView.java b/core/java/android/hardware/biometrics/PromptVerticalListContentView.java
index 38d32dc73ccb..02b2a50ade3c 100644
--- a/core/java/android/hardware/biometrics/PromptVerticalListContentView.java
+++ b/core/java/android/hardware/biometrics/PromptVerticalListContentView.java
@@ -29,9 +29,7 @@ import java.util.List;
/**
- * Contains the information of the template of vertical list content view for Biometric Prompt. Note
- * that there are limits on the item count and the number of characters allowed for each item's
- * text.
+ * Contains the information of the template of vertical list content view for Biometric Prompt.
* <p>
* Here's how you'd set a <code>PromptVerticalListContentView</code> on a Biometric Prompt:
* <pre class="prettyprint">
@@ -51,6 +49,8 @@ import java.util.List;
public final class PromptVerticalListContentView implements PromptContentViewParcelable {
private static final int MAX_ITEM_NUMBER = 20;
private static final int MAX_EACH_ITEM_CHARACTER_NUMBER = 640;
+ private static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225;
+
private final List<PromptContentItemParcelable> mContentList;
private final String mDescription;
@@ -150,51 +150,59 @@ public final class PromptVerticalListContentView implements PromptContentViewPar
*
* @param description The description to display.
* @return This builder.
+ * @throws IllegalArgumentException If description exceeds certain character limit.
*/
@NonNull
public Builder setDescription(@NonNull String description) {
+ if (description.length() > MAX_DESCRIPTION_CHARACTER_NUMBER) {
+ throw new IllegalStateException("The character number of description exceeds "
+ + MAX_DESCRIPTION_CHARACTER_NUMBER);
+ }
mDescription = description;
return this;
}
/**
- * Optional: Adds a list item in the current row. Maximum {@value MAX_ITEM_NUMBER} items in
- * total. The maximum length for each item is {@value MAX_EACH_ITEM_CHARACTER_NUMBER}
- * characters.
+ * Optional: Adds a list item in the current row.
*
* @param listItem The list item view to display
* @return This builder.
+ * @throws IllegalArgumentException If this list item exceeds certain character limits or
+ * the number of list items exceeds certain limit.
*/
@NonNull
public Builder addListItem(@NonNull PromptContentItem listItem) {
- if (doesListItemExceedsCharLimit(listItem)) {
- throw new IllegalStateException(
- "The character number of list item exceeds "
- + MAX_EACH_ITEM_CHARACTER_NUMBER);
- }
mContentList.add((PromptContentItemParcelable) listItem);
+ checkItemLimits(listItem);
return this;
}
-
/**
- * Optional: Adds a list item in the current row. Maximum {@value MAX_ITEM_NUMBER} items in
- * total. The maximum length for each item is {@value MAX_EACH_ITEM_CHARACTER_NUMBER}
- * characters.
+ * Optional: Adds a list item in the current row.
*
* @param listItem The list item view to display
- * @param index The position at which to add the item
+ * @param index The position at which to add the item
* @return This builder.
+ * @throws IllegalArgumentException If this list item exceeds certain character limits or
+ * the number of list items exceeds certain limit.
*/
@NonNull
public Builder addListItem(@NonNull PromptContentItem listItem, int index) {
+ mContentList.add(index, (PromptContentItemParcelable) listItem);
+ checkItemLimits(listItem);
+ return this;
+ }
+
+ private void checkItemLimits(@NonNull PromptContentItem listItem) {
if (doesListItemExceedsCharLimit(listItem)) {
throw new IllegalStateException(
"The character number of list item exceeds "
+ MAX_EACH_ITEM_CHARACTER_NUMBER);
}
- mContentList.add(index, (PromptContentItemParcelable) listItem);
- return this;
+ if (mContentList.size() > MAX_ITEM_NUMBER) {
+ throw new IllegalStateException(
+ "The number of list items exceeds " + MAX_ITEM_NUMBER);
+ }
}
private boolean doesListItemExceedsCharLimit(PromptContentItem listItem) {
@@ -217,10 +225,6 @@ public final class PromptVerticalListContentView implements PromptContentViewPar
*/
@NonNull
public PromptVerticalListContentView build() {
- if (mContentList.size() > MAX_ITEM_NUMBER) {
- throw new IllegalStateException(
- "The number of list items exceeds " + MAX_ITEM_NUMBER);
- }
return new PromptVerticalListContentView(mContentList, mDescription);
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31f2d8b13794..6431db9d174e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6778,7 +6778,7 @@
android:protectionLevel="signature" />
<!-- Allows an application to set the advanced features on BiometricDialog (SystemUI), including
- logo, logo description.
+ logo, logo description, and content view with more options button.
<p>Not for use by third-party applications.
@FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")
-->
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index b7e11a7fe261..14f3120b60b6 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -312,8 +312,8 @@ public class AuthService extends SystemService {
if (promptInfo.containsPrivateApiConfigurations()) {
checkInternalPermission();
}
- if (promptInfo.containsSetLogoApiConfigurations()) {
- checkManageBiometricPermission();
+ if (promptInfo.containsAdvancedApiConfigurations()) {
+ checkBiometricAdvancedPermission();
}
final long identity = Binder.clearCallingIdentity();
@@ -1029,7 +1029,7 @@ public class AuthService extends SystemService {
"Must have USE_BIOMETRIC_INTERNAL permission");
}
- private void checkManageBiometricPermission() {
+ private void checkBiometricAdvancedPermission() {
getContext().enforceCallingOrSelfPermission(SET_BIOMETRIC_DIALOG_ADVANCED,
"Must have SET_BIOMETRIC_DIALOG_ADVANCED permission");
}