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

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

Merge "Fix ui issues and add layout limit test for custom bp." into main

parents 00c8a878 5ad6c5b0
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.text.TextUtils;
import android.util.Log;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;

import java.lang.annotation.Retention;
@@ -70,7 +71,8 @@ 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;
    @VisibleForTesting
    static final int MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER = 30;

    /**
     * Error/help message will show for this amount of time.
@@ -223,7 +225,7 @@ 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
         * @throws IllegalArgumentException If logo description is null or exceeds certain character
         *                                  limit.
         */
        @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
@@ -232,7 +234,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        public BiometricPrompt.Builder setLogoDescription(@NonNull String logoDescription) {
            if (logoDescription == null
                    || logoDescription.length() > MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER) {
                throw new IllegalStateException(
                throw new IllegalArgumentException(
                        "Logo description passed in can not be null or exceed "
                                + MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER + " character number.");
            }
@@ -240,7 +242,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            return this;
        }


        /**
         * Required: Sets the title that will be shown on the prompt.
         * @param title The title to display.
+18 −12
Original line number Diff line number Diff line
@@ -29,19 +29,22 @@ import android.hardware.biometrics.BiometricPrompt.ButtonInfo;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.annotations.VisibleForTesting;

import java.util.concurrent.Executor;

/**
 * Contains the information of the template of content view with a more options button for Biometric
 * Prompt.
 * Contains the information of the template of content view with a more options button for
 * Biometric Prompt.
 * <p>
 * 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, and finally allow the app to decide how to proceed once
 * selected.
 * sign in.
 * <p>
 * Apps should avoid using this when possible 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 option, 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
@@ -59,7 +62,8 @@ 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;
    @VisibleForTesting
    static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225;

    private final String mDescription;
    private DialogInterface.OnClickListener mListener;
@@ -132,14 +136,16 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
        }
    };

    /**
     * A builder that collects arguments to be shown on the content view with more options button.
     */
    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.
         * Optional: Sets a description that will be shown on the content view.
         *
         * @param description The description to display.
         * @return This builder.
@@ -149,7 +155,7 @@ public final class PromptContentViewWithMoreOptionsButton implements PromptConte
        @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 "
                throw new IllegalArgumentException("The character number of description exceeds "
                        + MAX_DESCRIPTION_CHARACTER_NUMBER);
            }
            mDescription = description;
+11 −6
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;

@@ -47,9 +49,12 @@ import java.util.List;
 */
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
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;
    @VisibleForTesting
    static final int MAX_ITEM_NUMBER = 20;
    @VisibleForTesting
    static final int MAX_EACH_ITEM_CHARACTER_NUMBER = 640;
    @VisibleForTesting
    static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225;

    private final List<PromptContentItemParcelable> mContentList;
    private final String mDescription;
@@ -155,7 +160,7 @@ public final class PromptVerticalListContentView implements PromptContentViewPar
        @NonNull
        public Builder setDescription(@NonNull String description) {
            if (description.length() > MAX_DESCRIPTION_CHARACTER_NUMBER) {
                throw new IllegalStateException("The character number of description exceeds "
                throw new IllegalArgumentException("The character number of description exceeds "
                        + MAX_DESCRIPTION_CHARACTER_NUMBER);
            }
            mDescription = description;
@@ -195,12 +200,12 @@ public final class PromptVerticalListContentView implements PromptContentViewPar

        private void checkItemLimits(@NonNull PromptContentItem listItem) {
            if (doesListItemExceedsCharLimit(listItem)) {
                throw new IllegalStateException(
                throw new IllegalArgumentException(
                        "The character number of list item exceeds "
                                + MAX_EACH_ITEM_CHARACTER_NUMBER);
            }
            if (mContentList.size() > MAX_ITEM_NUMBER) {
                throw new IllegalStateException(
                throw new IllegalArgumentException(
                        "The number of list items exceeds " + MAX_ITEM_NUMBER);
            }
        }
+122 −4
Original line number Diff line number Diff line
@@ -16,6 +16,14 @@

package android.hardware.biometrics;

import static android.hardware.biometrics.BiometricPrompt.MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER;
import static android.hardware.biometrics.PromptContentViewWithMoreOptionsButton.MAX_DESCRIPTION_CHARACTER_NUMBER;
import static android.hardware.biometrics.PromptVerticalListContentView.MAX_EACH_ITEM_CHARACTER_NUMBER;
import static android.hardware.biometrics.PromptVerticalListContentView.MAX_ITEM_NUMBER;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -40,6 +48,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.MockitoRule;

import java.util.Random;
import java.util.concurrent.Executor;


@@ -86,7 +95,8 @@ public class BiometricPromptTest {
                    @Override
                    public void onAuthenticationError(int errorCode, CharSequence errString) {
                        super.onAuthenticationError(errorCode, errString);
            }};
                    }
                };
        mBiometricPrompt.authenticate(mCancellationSignal, mExecutor, callback);
        mLooper.dispatchAll();

@@ -99,4 +109,112 @@ public class BiometricPromptTest {

        verify(mService).cancelAuthentication(any(), anyString(), anyLong());
    }

    @Test
    public void testLogoDescription_null() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> new BiometricPrompt.Builder(mContext).setLogoDescription(null)
        );

        assertThat(e).hasMessageThat().contains(
                "Logo description passed in can not be null or exceed");
    }

    @Test
    public void testLogoDescription_charLimit() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> new BiometricPrompt.Builder(mContext).setLogoDescription(
                        generateRandomString(MAX_LOGO_DESCRIPTION_CHARACTER_NUMBER + 1))
        );

        assertThat(e).hasMessageThat().contains(
                "Logo description passed in can not be null or exceed");
    }

    @Test
    public void testMoreOptionsButton_descriptionCharLimit() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> new PromptContentViewWithMoreOptionsButton.Builder().setDescription(
                        generateRandomString(MAX_DESCRIPTION_CHARACTER_NUMBER + 1))
        );

        assertThat(e).hasMessageThat().contains(
                "The character number of description exceeds ");
    }

    @Test
    public void testMoreOptionsButton_ExecutorNull() {
        PromptContentViewWithMoreOptionsButton.Builder builder =
                new PromptContentViewWithMoreOptionsButton.Builder().setMoreOptionsButtonListener(
                        null, null);
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                builder::build
        );

        assertThat(e).hasMessageThat().contains(
                "The executor for the listener of more options button on prompt content must be "
                        + "set");
    }

    @Test
    public void testMoreOptionsButton_ListenerNull() {
        PromptContentViewWithMoreOptionsButton.Builder builder =
                new PromptContentViewWithMoreOptionsButton.Builder().setMoreOptionsButtonListener(
                        mExecutor, null);
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                builder::build
        );

        assertThat(e).hasMessageThat().contains(
                "The listener of more options button on prompt content must be set");
    }

    @Test
    public void testVerticalList_descriptionCharLimit() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> new PromptVerticalListContentView.Builder().setDescription(
                        generateRandomString(MAX_DESCRIPTION_CHARACTER_NUMBER + 1))
        );

        assertThat(e).hasMessageThat().contains(
                "The character number of description exceeds ");
    }

    @Test
    public void testVerticalList_itemCharLimit() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> new PromptVerticalListContentView.Builder().addListItem(
                        new PromptContentItemBulletedText(
                                generateRandomString(MAX_EACH_ITEM_CHARACTER_NUMBER + 1)))
        );

        assertThat(e).hasMessageThat().contains(
                "The character number of list item exceeds ");
    }

    @Test
    public void testVerticalList_itemNumLimit() {
        PromptVerticalListContentView.Builder builder = new PromptVerticalListContentView.Builder();

        for (int i = 0; i < MAX_ITEM_NUMBER; i++) {
            builder.addListItem(new PromptContentItemBulletedText(generateRandomString(10)));
        }

        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> builder.addListItem(
                        new PromptContentItemBulletedText(generateRandomString(10)))
        );

        assertThat(e).hasMessageThat().contains(
                "The number of list items exceeds ");
    }

    private String generateRandomString(int charNum) {
        final Random random = new Random();
        final StringBuilder longString = new StringBuilder(charNum);
        for (int j = 0; j < charNum; j++) {
            longString.append(random.nextInt(10));
        }
        return longString.toString();
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -224,6 +224,7 @@
    <style name="TextAppearance.AuthCredential.ContentViewListItem" parent="TextAppearance.Material3.BodySmall">
        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
        <item name="android:paddingTop">@dimen/biometric_prompt_content_list_item_padding_top</item>
        <item name="android:breakStrategy">high_quality</item>
    </style>

    <style name="TextAppearance.AuthCredential.Indicator" parent="TextAppearance.Material3.BodyMedium">
Loading