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

Commit ac6113b4 authored by Kevin Chyn's avatar Kevin Chyn Committed by Automerger Merge Worker
Browse files

Merge "Add AuthBiometricUdfpsView for portrait" am: cd0710b0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12925499

Change-Id: I5ddd360140f8b763018f38c25cafb0d288d210b3
parents 1830221d cd0710b0
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -43,24 +43,36 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
     * The location of the center of the sensor if applicable. For example, sensors of type
     * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
     * distance in pixels, measured from the left edge of the screen.
     * TODO: Value should be provided from the HAL
     */
    public final int sensorLocationX = 540;
    public final int sensorLocationX;

    /**
     * The location of the center of the sensor if applicable. For example, sensors of type
     * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
     * distance in pixels, measured from the top edge of the screen.
     * TODO: Value should be provided from the HAL
     *
     */
    public final int sensorLocationY = 1636;
    public final int sensorLocationY;

    /**
     * The radius of the sensor if applicable. For example, sensors of type
     * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
     * of the sensor, in pixels.
     */
    public final int sensorRadius = 130;
    public final int sensorRadius;

    public FingerprintSensorPropertiesInternal(int sensorId,
            @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
            @FingerprintSensorProperties.SensorType int sensorType,
            boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
            int sensorRadius) {
        super(sensorId, strength, maxEnrollmentsPerUser);
        this.sensorType = sensorType;
        this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
        this.sensorLocationX = sensorLocationX;
        this.sensorLocationY = sensorLocationY;
        this.sensorRadius = sensorRadius;
    }

    /**
     * Initializes SensorProperties with specified values
@@ -69,15 +81,19 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
            @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
            @FingerprintSensorProperties.SensorType int sensorType,
            boolean resetLockoutRequiresHardwareAuthToken) {
        super(sensorId, strength, maxEnrollmentsPerUser);
        this.sensorType = sensorType;
        this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
        // TODO: Value should be provided from the HAL
        this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
                resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
                1636 /* sensorLocationY */, 130 /* sensorRadius */);
    }

    protected FingerprintSensorPropertiesInternal(Parcel in) {
        super(in);
        sensorType = in.readInt();
        resetLockoutRequiresHardwareAuthToken = in.readBoolean();
        sensorLocationX = in.readInt();
        sensorLocationY = in.readInt();
        sensorRadius = in.readInt();
    }

    public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
@@ -103,6 +119,9 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
        super.writeToParcel(dest, flags);
        dest.writeInt(sensorType);
        dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
        dest.writeInt(sensorLocationX);
        dest.writeInt(sensorLocationY);
        dest.writeInt(sensorRadius);
    }

    public boolean isAnyUdfpsType() {
+28 −7
Original line number Diff line number Diff line
@@ -37,13 +37,32 @@
        android:gravity="@integer/biometric_dialog_text_gravity"
        style="@style/TextAppearance.AuthCredential.Description"/>

    <Space android:id="@+id/space_above_icon"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:visibility="visible" />

    <!-- Use a frame layout since certain biometrics (such as UDFPS) require the icon to be centered
         within a certain area on the display. This makes it easy to 1) guarantee max size, and
         2) center the icon within the reserved area. -->
    <FrameLayout android:id="@+id/biometric_icon_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal">
        <ImageView
            android:id="@+id/biometric_icon"
            android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
            android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
        android:paddingTop="48dp"
        android:layout_gravity="center_horizontal"
            android:layout_gravity="center"
            android:scaleType="fitXY" />
    </FrameLayout>

    <!-- For sensors such as UDFPS, this view is used during custom measurement/layoutto add extra
         padding so that the biometric icon is always in the right physical position. -->
    <Space android:id="@+id/space_below_icon"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:visibility="gone" />

    <TextView
        android:id="@+id/indicator"
@@ -54,6 +73,8 @@
        android:textSize="12sp"
        android:gravity="center_horizontal"
        android:accessibilityLiveRegion="polite"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:textColor="@color/biometric_dialog_gray"/>

    <LinearLayout
+26 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2020 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.
  -->

<com.android.systemui.biometrics.AuthBiometricUdfpsView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/contents"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <include layout="@layout/auth_biometric_contents"/>

</com.android.systemui.biometrics.AuthBiometricUdfpsView>
 No newline at end of file
+2 −2
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
        mIconController.updateState(mState, newState);

        if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
                (newState == STATE_AUTHENTICATING && mSize == AuthDialog.SIZE_MEDIUM)) {
                (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
            resetErrorView(mContext, mIndicatorView);
        }

@@ -194,7 +194,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {

    @Override
    public void onAuthenticationFailed(String failureReason) {
        if (mSize == AuthDialog.SIZE_MEDIUM) {
        if (getSize() == AuthDialog.SIZE_MEDIUM) {
            mTryAgainButton.setVisibility(View.VISIBLE);
            mPositiveButton.setVisibility(View.GONE);
        }
+146 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.systemui.biometrics;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;

import com.android.systemui.R;

/**
 * Manages the layout for under-display fingerprint sensors (UDFPS). Ensures that UI elements
 * do not overlap with
 */
public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {

    private static final String TAG = "AuthBiometricUdfpsView";

    @Nullable private FingerprintSensorPropertiesInternal mSensorProps;

    public AuthBiometricUdfpsView(Context context) {
        this(context, null /* attrs */);
    }

    public AuthBiometricUdfpsView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    void setSensorProps(@NonNull FingerprintSensorPropertiesInternal prop) {
        mSensorProps = prop;
    }

    /**
     * For devices where the sensor is too high up, calculates the amount of padding necessary to
     * move/center the biometric icon within the sensor's physical location.
     */
    static int calculateBottomSpacerHeight(int displayHeightPx, int navbarHeightPx,
            int dialogBottomMarginPx, @NonNull View buttonBar, @NonNull View textIndicator,
            @NonNull FingerprintSensorPropertiesInternal sensorProperties) {
        final int sensorDistanceFromBottom = displayHeightPx - sensorProperties.sensorLocationY
                - sensorProperties.sensorRadius;

        final int spacerHeight = sensorDistanceFromBottom
                - textIndicator.getMeasuredHeight()
                - buttonBar.getMeasuredHeight()
                - dialogBottomMarginPx
                - navbarHeightPx;

        Log.d(TAG, "Display height: " + displayHeightPx
                + ", Distance from bottom: " + sensorDistanceFromBottom
                + ", Bottom margin: " + dialogBottomMarginPx
                + ", Navbar height: " + navbarHeightPx
                + ", Spacer height: " + spacerHeight);

        return spacerHeight;
    }

    @Override
    AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
        final View spaceBelowIcon = findViewById(R.id.space_below_icon);
        spaceBelowIcon.setVisibility(View.VISIBLE);

        // Get the height of the everything below the icon. Currently, that's the indicator and
        // button bar
        final View textIndicator = findViewById(R.id.indicator);
        final View buttonBar = findViewById(R.id.button_bar);

        // Figure out where the bottom of the sensor anim should be.
        // Navbar + dialogMargin + buttonBar + textIndicator + spacerHeight = sensorDistFromBottom
        final int dialogBottomMarginPx = getResources()
                .getDimensionPixelSize(R.dimen.biometric_dialog_border_padding);
        final WindowManager wm = getContext().getSystemService(WindowManager.class);
        final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
        final int navbarHeight = wm.getCurrentWindowMetrics().getWindowInsets()
                .getInsets(WindowInsets.Type.navigationBars()).toRect().height();
        final int displayHeight = bounds.height();

        final int spacerHeight = calculateBottomSpacerHeight(displayHeight, navbarHeight,
                dialogBottomMarginPx, buttonBar, textIndicator, mSensorProps);

        // Go through each of the children and do the custom measurement.
        int totalHeight = 0;
        final int numChildren = getChildCount();
        final int sensorDiameter = mSensorProps.sensorRadius * 2;
        for (int i = 0; i < numChildren; i++) {
            final View child = getChildAt(i);

            if (child.getId() == R.id.biometric_icon_frame) {
                // Create a frame that's exactly the size of the sensor circle
                child.measure(
                        MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
            } else if (child.getId() == R.id.biometric_icon) {
                // Icon should never be larger than the circle
                child.measure(
                        MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
                        MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
            } else if (child.getId() == R.id.space_above_icon) {
                child.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
                                MeasureSpec.EXACTLY));
            } else if (child.getId() == R.id.button_bar) {
                child.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
                                MeasureSpec.EXACTLY));
            } else if (child.getId() == R.id.space_below_icon) {
                // Set the spacer height so the fingerprint icon is on the physical sensor area
                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(spacerHeight, MeasureSpec.EXACTLY));
            } else {
                child.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
            }

            if (child.getVisibility() != View.GONE) {
                totalHeight += child.getMeasuredHeight();
            }
        }

        return new AuthDialog.LayoutParams(width, totalHeight);
    }
}
Loading