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

Commit cd0710b0 authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge "Add AuthBiometricUdfpsView for portrait"

parents 136ce9f5 90e442a7
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