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

Commit 05c83b71 authored by Joe Bolinger's avatar Joe Bolinger
Browse files

Migrate small UDFPS classes to kotlin and backfill missing tests.

Bug: 205875955
Test: atest UdfpsViewTest UdfpsControllerTest
Test: manual (enroll manually and BP test app)
Change-Id: Ia09f18bffe943ecdf7a73c71faae6f2e2d40e359
parent 5d8375c4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import android.widget.FrameLayout;
 * - sends sensor rect updates to fingerprint drawable
 * - optionally can override dozeTimeTick to adjust views for burn-in mitigation
 */
abstract class UdfpsAnimationView extends FrameLayout {
public abstract class UdfpsAnimationView extends FrameLayout {
    // mAlpha takes into consideration the status bar expansion amount to fade out icon when
    // the status bar is expanded
    private int mAlpha;
+170 −0
Original line number Diff line number Diff line
@@ -13,23 +13,19 @@
 * 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.graphics.PointF;
import android.graphics.RectF;

import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.util.ViewController;

import java.io.FileDescriptor;
import java.io.PrintWriter;
package com.android.systemui.biometrics

import android.graphics.PointF
import android.graphics.RectF
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
import com.android.systemui.util.ViewController
import java.io.FileDescriptor
import java.io.PrintWriter

/**
 * Handles:
@@ -41,162 +37,134 @@ import java.io.PrintWriter;
 * - sensor position changes
 * - doze time event
 */
abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
        extends ViewController<T> implements Dumpable {
    @NonNull final StatusBarStateController mStatusBarStateController;
    @NonNull final PanelExpansionStateManager mPanelExpansionStateManager;
    @NonNull final SystemUIDialogManager mDialogManager;
    @NonNull final DumpManager mDumpManger;

    boolean mNotificationShadeVisible;

    protected UdfpsAnimationViewController(
            T view,
            @NonNull StatusBarStateController statusBarStateController,
            @NonNull PanelExpansionStateManager panelExpansionStateManager,
            @NonNull SystemUIDialogManager dialogManager,
            @NonNull DumpManager dumpManager) {
        super(view);
        mStatusBarStateController = statusBarStateController;
        mPanelExpansionStateManager = panelExpansionStateManager;
        mDialogManager = dialogManager;
        mDumpManger = dumpManager;
    }
abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>(
    view: T,
    protected val statusBarStateController: StatusBarStateController,
    protected val panelExpansionStateManager: PanelExpansionStateManager,
    protected val dialogManager: SystemUIDialogManager,
    private val dumpManager: DumpManager
) : ViewController<T>(view), Dumpable {

    abstract @NonNull String getTag();
    protected abstract val tag: String

    @Override
    protected void onViewAttached() {
        mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
        mDialogManager.registerListener(mDialogListener);
        mDumpManger.registerDumpable(getDumpTag(), this);
    }
    private val view: T
        get() = mView!!

    private val dialogListener = SystemUIDialogManager.Listener { updatePauseAuth() }

    @Override
    protected void onViewDetached() {
        mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
        mDialogManager.unregisterListener(mDialogListener);
        mDumpManger.unregisterDumpable(getDumpTag());
    private val panelExpansionListener =
        PanelExpansionListener { fraction, expanded, tracking ->
            // Notification shade can be expanded but not visible (fraction: 0.0), for example
            // when a heads-up notification (HUN) is showing.
            notificationShadeVisible = expanded && fraction > 0f
            view.onExpansionChanged(fraction)
            updatePauseAuth()
        }

    /** If the notification shade is visible. */
    var notificationShadeVisible: Boolean = false

    /**
     * in some cases, onViewAttached is called for the newly added view using an instance of
     * this controller before onViewDetached is called on the previous view, so we must have a
     * unique dump tag per instance of this class
     * @return a unique tag for this instance of this class
     * The amount of translation needed if the view currently requires the user to touch
     * somewhere other than the exact center of the sensor. For example, this can happen
     * during guided enrollment.
     */
    private String getDumpTag() {
        return getTag() + " (" + this + ")";
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("mNotificationShadeVisible=" + mNotificationShadeVisible);
        pw.println("shouldPauseAuth()=" + shouldPauseAuth());
        pw.println("isPauseAuth=" + mView.isPauseAuth());
    }
    open val touchTranslation: PointF = PointF(0f, 0f)

    /**
     * Returns true if the fingerprint manager is running but we want to temporarily pause
     * authentication.
     * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
     * window to draw within.
     */
    boolean shouldPauseAuth() {
        return mNotificationShadeVisible
                || mDialogManager.shouldHideAffordance();
    }
    open val paddingX: Int = 0

    /**
     * Send pause auth update to our view.
     * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
     * window to draw within.
     */
    void updatePauseAuth() {
        if (mView.setPauseAuth(shouldPauseAuth())) {
            mView.postInvalidate();
    open val paddingY: Int = 0

    override fun onViewAttached() {
        panelExpansionStateManager.addExpansionListener(panelExpansionListener)
        dialogManager.registerListener(dialogListener)
        dumpManager.registerDumpable(dumpTag, this)
    }

    override fun onViewDetached() {
        panelExpansionStateManager.removeExpansionListener(panelExpansionListener)
        dialogManager.unregisterListener(dialogListener)
        dumpManager.unregisterDumpable(dumpTag)
    }

    /**
     * Send sensor position change to our view. This rect contains paddingX and paddingY.
     * in some cases, onViewAttached is called for the newly added view using an instance of
     * this controller before onViewDetached is called on the previous view, so we must have a
     * unique [dumpTag] per instance of this class.
     */
    void onSensorRectUpdated(RectF sensorRect) {
        mView.onSensorRectUpdated(sensorRect);
    private val dumpTag = "$tag ($this)"

    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
        pw.println("mNotificationShadeVisible=$notificationShadeVisible")
        pw.println("shouldPauseAuth()=" + shouldPauseAuth())
        pw.println("isPauseAuth=" + view.isPauseAuth)
    }

    /**
     * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
     * Returns true if the fingerprint manager is running, but we want to temporarily pause
     * authentication.
     */
    void dozeTimeTick() {
        if (mView.dozeTimeTick()) {
            mView.postInvalidate();
        }
    open fun shouldPauseAuth(): Boolean {
        return notificationShadeVisible || dialogManager.shouldHideAffordance()
    }

    /**
     * @return the amount of translation needed if the view currently requires the user to touch
     *         somewhere other than the exact center of the sensor. For example, this can happen
     *         during guided enrollment.
     * Send pause auth update to our view.
     */
    PointF getTouchTranslation() {
        return new PointF(0, 0);
    fun updatePauseAuth() {
        if (view.setPauseAuth(shouldPauseAuth())) {
            view.postInvalidate()
        }
    }

    /**
     * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
     * window to draw within.
     * @return
     * Send sensor position change to our view. This rect contains paddingX and paddingY.
     */
    int getPaddingX() {
        return 0;
    fun onSensorRectUpdated(sensorRect: RectF) {
        view.onSensorRectUpdated(sensorRect)
    }

    /**
     * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
     * window to draw within.
     * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
     */
    int getPaddingY() {
        return 0;
    fun dozeTimeTick() {
        if (view.dozeTimeTick()) {
            view.postInvalidate()
        }
    }

    /**
     * Udfps has started illuminating and the fingerprint manager is working on authenticating.
     */
    void onIlluminationStarting() {
        mView.onIlluminationStarting();
        mView.postInvalidate();
    fun onIlluminationStarting() {
        view.onIlluminationStarting()
        view.postInvalidate()
    }

    /**
     * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
     * authenticate.
     */
    void onIlluminationStopped() {
        mView.onIlluminationStopped();
        mView.postInvalidate();
    fun onIlluminationStopped() {
        view.onIlluminationStopped()
        view.postInvalidate()
    }

    /**
     * Whether to listen for touches outside of the view.
     */
    boolean listenForTouchesOutsideView() {
        return false;
    }
    open fun listenForTouchesOutsideView(): Boolean = false

    /**
     * Called on touches outside of the view if listenForTouchesOutsideView returns true
     */
    void onTouchOutsideView() { }

    private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() {
        @Override
        public void onPanelExpansionChanged(
                float fraction, boolean expanded, boolean tracking) {
            // Notification shade can be expanded but not visible (fraction: 0.0), for example
            // when a heads-up notification (HUN) is showing.
            mNotificationShadeVisible = expanded && fraction > 0f;
            mView.onExpansionChanged(fraction);
            updatePauseAuth();
        }
    };

    private final SystemUIDialogManager.Listener mDialogListener =
            (shouldHide) -> updatePauseAuth();
    open fun onTouchOutsideView() {}
}
 No newline at end of file
+8 −18
Original line number Diff line number Diff line
@@ -13,33 +13,23 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.biometrics

package com.android.systemui.biometrics;

import android.content.Context;
import android.util.AttributeSet;

import androidx.annotation.Nullable;
import android.content.Context
import android.util.AttributeSet

/**
 * Class that coordinates non-HBM animations during BiometricPrompt.
 *
 * Currently doesn't draw anything.
 *
 * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
 * Note that [AuthBiometricUdfpsView] also shows UDFPS animations. At some point we should
 * de-dupe this if necessary.
 */
public class UdfpsBpView extends UdfpsAnimationView {
    private UdfpsFpDrawable mFingerprintDrawable;
class UdfpsBpView(context: Context, attrs: AttributeSet?) : UdfpsAnimationView(context, attrs) {

    public UdfpsBpView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    // Drawable isn't ever added to the view, so we don't currently show anything
        mFingerprintDrawable = new UdfpsFpDrawable(mContext);
    }
    private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)

    @Override
    UdfpsDrawable getDrawable() {
        return mFingerprintDrawable;
    }
    override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
}
+19 −23
Original line number Diff line number Diff line
@@ -13,32 +13,28 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.biometrics

package com.android.systemui.biometrics;

import android.annotation.NonNull;

import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager

/**
 * Class that coordinates non-HBM animations for biometric prompt.
 */
class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
    protected UdfpsBpViewController(
            @NonNull UdfpsBpView view,
            @NonNull StatusBarStateController statusBarStateController,
            @NonNull PanelExpansionStateManager panelExpansionStateManager,
            @NonNull SystemUIDialogManager systemUIDialogManager,
            @NonNull DumpManager dumpManager) {
        super(view, statusBarStateController, panelExpansionStateManager,
                systemUIDialogManager, dumpManager);
    }

    @Override
    @NonNull String getTag() {
        return "UdfpsBpViewController";
    }
class UdfpsBpViewController(
    view: UdfpsBpView,
    statusBarStateController: StatusBarStateController,
    panelExpansionStateManager: PanelExpansionStateManager,
    systemUIDialogManager: SystemUIDialogManager,
    dumpManager: DumpManager
) : UdfpsAnimationViewController<UdfpsBpView>(
    view,
    statusBarStateController,
    panelExpansionStateManager,
    systemUIDialogManager,
    dumpManager
) {
    override val tag = "UdfpsBpViewController"
}
+0 −113
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.content.Context;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.util.PathParser;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.systemui.R;

/**
 * Abstract base class for drawable displayed when the finger is not touching the
 * sensor area.
 */
public abstract class UdfpsDrawable extends Drawable {
    static final float DEFAULT_STROKE_WIDTH = 3f;

    @NonNull final Context mContext;
    @NonNull final ShapeDrawable mFingerprintDrawable;
    private final Paint mPaint;
    private boolean mIlluminationShowing;

    int mAlpha = 255; // 0 - 255
    public UdfpsDrawable(@NonNull Context context) {
        mContext = context;
        final String fpPath = context.getResources().getString(R.string.config_udfpsIcon);
        mFingerprintDrawable = new ShapeDrawable(
                new PathShape(PathParser.createPathFromPathData(fpPath), 72, 72));
        mFingerprintDrawable.mutate();

        mPaint = mFingerprintDrawable.getPaint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        setStrokeWidth(DEFAULT_STROKE_WIDTH);
    }

    void setStrokeWidth(float strokeWidth) {
        mPaint.setStrokeWidth(strokeWidth);
        invalidateSelf();
    }

    /**
     * @param sensorRect the rect coordinates for the sensor area
     */
    public void onSensorRectUpdated(@NonNull RectF sensorRect) {
        final int margin =  (int) sensorRect.height() / 8;

        final Rect bounds = new Rect((int) sensorRect.left + margin,
                (int) sensorRect.top + margin,
                (int) sensorRect.right - margin,
                (int) sensorRect.bottom - margin);
        updateFingerprintIconBounds(bounds);
    }

    /**
     * Bounds for the fingerprint icon
     */
    protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
        mFingerprintDrawable.setBounds(bounds);
        invalidateSelf();
    }

    @Override
    public void setAlpha(int alpha) {
        mAlpha = alpha;
        mFingerprintDrawable.setAlpha(mAlpha);
        invalidateSelf();
    }

    boolean isIlluminationShowing() {
        return mIlluminationShowing;
    }

    void setIlluminationShowing(boolean showing) {
        if (mIlluminationShowing == showing) {
            return;
        }
        mIlluminationShowing = showing;
        invalidateSelf();
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
    }

    @Override
    public int getOpacity() {
        return 0;
    }
}
Loading