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

Commit c3a18331 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

Add anti burn-in logic for UdfpsView

Bug: 164503336
Test: manual
Test: atest com.android.systemui

Change-Id: I011931663243910ef94844a5da930ee8047c2e22
parent dc1e4a97
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1036,6 +1036,11 @@
    <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
    <dimen name="default_burn_in_prevention_offset">15dp</dimen>

    <!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either
         direction that elements aer moved to prevent burn-in on AOD-->
    <dimen name="udfps_burn_in_offset_x">8dp</dimen>
    <dimen name="udfps_burn_in_offset_y">8dp</dimen>

    <dimen name="corner_size">8dp</dimen>
    <dimen name="top_padding">0dp</dimen>
    <dimen name="bottom_padding">48dp</dimen>
+20 −6
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.systemui.SystemUI;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;

import java.util.List;
@@ -62,12 +64,13 @@ import javax.inject.Singleton;
 */
@Singleton
public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        AuthDialogCallback {
        AuthDialogCallback, DozeReceiver {

    private static final String TAG = "BiometricPrompt/AuthController";
    private static final String TAG = "AuthController";
    private static final boolean DEBUG = true;

    private final CommandQueue mCommandQueue;
    private final StatusBarStateController mStatusBarStateController;
    private final Injector mInjector;

    // TODO: These should just be saved from onSaveState
@@ -77,6 +80,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,

    private Handler mHandler = new Handler(Looper.getMainLooper());
    private WindowManager mWindowManager;
    @Nullable
    private UdfpsController mUdfpsController;
    @VisibleForTesting
    IActivityTaskManager mActivityTaskManager;
@@ -142,6 +146,13 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        }
    };

    @Override
    public void dozeTimeTick() {
        if (mUdfpsController != null) {
            mUdfpsController.dozeTimeTick();
        }
    }

    @Override
    public void onTryAgainPressed() {
        if (mReceiver == null) {
@@ -251,14 +262,17 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
    }

    @Inject
    public AuthController(Context context, CommandQueue commandQueue) {
        this(context, commandQueue, new Injector());
    public AuthController(Context context, CommandQueue commandQueue,
            StatusBarStateController statusBarStateController) {
        this(context, commandQueue, statusBarStateController, new Injector());
    }

    @VisibleForTesting
    AuthController(Context context, CommandQueue commandQueue, Injector injector) {
    AuthController(Context context, CommandQueue commandQueue,
            StatusBarStateController statusBarStateController, Injector injector) {
        super(context);
        mCommandQueue = commandQueue;
        mStatusBarStateController = statusBarStateController;
        mInjector = injector;

        IntentFilter filter = new IntentFilter();
@@ -280,7 +294,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
                    fpm.getSensorProperties();
            for (FingerprintSensorProperties props : fingerprintSensorProperties) {
                if (props.sensorType == FingerprintSensorProperties.TYPE_UDFPS) {
                    mUdfpsController = new UdfpsController(mContext);
                    mUdfpsController = new UdfpsController(mContext, mStatusBarStateController);
                    break;
                }
            }
+29 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.biometrics;

import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
@@ -39,6 +40,8 @@ import android.view.WindowManager;

import com.android.internal.BrightnessSynchronizer;
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;

import java.io.FileWriter;
import java.io.IOException;
@@ -47,7 +50,7 @@ import java.io.IOException;
 * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
 * and coordinates triggering of the high-brightness mode (HBM).
 */
class UdfpsController {
class UdfpsController implements DozeReceiver {
    private static final String TAG = "UdfpsController";
    // Gamma approximation for the sRGB color space.
    private static final float DISPLAY_GAMMA = 2.2f;
@@ -62,6 +65,7 @@ class UdfpsController {
    private final String mHbmPath;
    private final String mHbmEnableCommand;
    private final String mHbmDisableCommand;
    private final boolean mHbmSupported;
    // Brightness in nits in the high-brightness mode.
    private final float mHbmNits;
    // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to a
@@ -122,7 +126,8 @@ class UdfpsController {
        }
    };

    UdfpsController(Context context) {
    UdfpsController(@NonNull Context context,
            @NonNull StatusBarStateController statusBarStateController) {
        mFingerprintManager = context.getSystemService(FingerprintManager.class);
        mWindowManager = context.getSystemService(WindowManager.class);
        mContentResolver = context.getContentResolver();
@@ -135,7 +140,9 @@ class UdfpsController {
        mHbmEnableCommand = context.getResources().getString(R.string.udfps_hbm_enable_command);
        mHbmDisableCommand = context.getResources().getString(R.string.udfps_hbm_disable_command);

        mView.setHbmSupported(!TextUtils.isEmpty(mHbmPath));
        mHbmSupported = !TextUtils.isEmpty(mHbmPath);
        mView.setHbmSupported(mHbmSupported);
        statusBarStateController.addCallback(mView);

        // This range only consists of the minimum and maximum values, which only cover
        // non-high-brightness mode.
@@ -170,6 +177,11 @@ class UdfpsController {
        mIsOverlayShowing = false;
    }

    @Override
    public void dozeTimeTick() {
        mView.dozeTimeTick();
    }

    private void showUdfpsOverlay() {
        mHandler.post(() -> {
            if (!mIsOverlayShowing) {
@@ -232,9 +244,11 @@ class UdfpsController {
        mView.setScrimAlpha(computeScrimOpacity());
        mView.showScrimAndDot();
        try {
            if (mHbmSupported) {
                FileWriter fw = new FileWriter(mHbmPath);
                fw.write(mHbmEnableCommand);
                fw.close();
            }
            mFingerprintManager.onFingerDown(x, y, minor, major);
        } catch (IOException e) {
            mView.hideScrimAndDot();
@@ -246,6 +260,7 @@ class UdfpsController {
        mFingerprintManager.onFingerUp();
        // Hiding the scrim before disabling HBM results in less noticeable flicker.
        mView.hideScrimAndDot();
        if (mHbmSupported) {
            try {
                FileWriter fw = new FileWriter(mHbmPath);
                fw.write(mHbmDisableCommand);
@@ -255,6 +270,7 @@ class UdfpsController {
                Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage());
            }
        }
    }

    private static WindowManager.LayoutParams createLayoutParams(Context context) {
        Point displaySize = new Point();
+51 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.biometrics;

import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -23,17 +25,22 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.view.View;
import android.view.ViewTreeObserver;

import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;

/**
 * A full screen view with a configurable illumination dot and scrim.
 */
public class UdfpsView extends View {
public class UdfpsView extends View implements DozeReceiver,
        StatusBarStateController.StateListener {
    private static final String TAG = "UdfpsView";

    // Values in pixels.
@@ -53,10 +60,17 @@ public class UdfpsView extends View {
    private final float mSensorRadius;
    private final float mSensorMarginBottom;
    private final float mSensorTouchAreaCoefficient;
    private final int mMaxBurnInOffsetX;
    private final int mMaxBurnInOffsetY;

    private final Rect mTouchableRegion;
    private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;

    // AOD anti-burn-in offsets
    private float mInterpolatedDarkAmount;
    private float mBurnInOffsetX;
    private float mBurnInOffsetY;

    private boolean mIsScrimShowing;
    private boolean mHbmSupported;
    private String mDebugMessage;
@@ -85,6 +99,11 @@ public class UdfpsView extends View {
            a.recycle();
        }

        mMaxBurnInOffsetX = getResources()
                .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
        mMaxBurnInOffsetY = getResources()
                .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);

        mScrimRect = new Rect();
        mScrimPaint = new Paint(0 /* flags */);
        mScrimPaint.setColor(Color.BLACK);
@@ -113,6 +132,29 @@ public class UdfpsView extends View {
        mIsScrimShowing = false;
    }

    @Override
    public void dozeTimeTick() {
        updateAodPosition();
    }

    @Override
    public void onDozeAmountChanged(float linear, float eased) {
        mInterpolatedDarkAmount = eased;
        updateAodPosition();
    }

    private void updateAodPosition() {
        mBurnInOffsetX = MathUtils.lerp(0f,
                getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
                        - mMaxBurnInOffsetX,
                mInterpolatedDarkAmount);
        mBurnInOffsetY = MathUtils.lerp(0f,
                getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
                        - 0.5f * mMaxBurnInOffsetY,
                mInterpolatedDarkAmount);
        postInvalidate();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
@@ -142,14 +184,20 @@ public class UdfpsView extends View {
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mIsScrimShowing && mHbmSupported) {
            // Only draw the scrim if HBM is supported.
            canvas.drawRect(mScrimRect, mScrimPaint);
        }

        canvas.drawText(mDebugMessage, 0, 60, mDebugTextPaint);

        // Translation should affect everything but the scrim.
        canvas.save();
        canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
        if (!TextUtils.isEmpty(mDebugMessage)) {
            canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
        }
        canvas.drawOval(mSensorRect, mSensorPaint);
        canvas.restore();
    }

    void setHbmSupported(boolean hbmSupported) {
+6 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.doze.DozeReceiver;
@@ -88,6 +89,7 @@ public final class DozeServiceHost implements DozeHost {
    private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
    private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
    private final LockscreenLockIconController mLockscreenLockIconController;
    private final AuthController mAuthController;
    private NotificationIconAreaController mNotificationIconAreaController;
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private NotificationPanelViewController mNotificationPanel;
@@ -110,7 +112,8 @@ public final class DozeServiceHost implements DozeHost {
            PulseExpansionHandler pulseExpansionHandler,
            NotificationShadeWindowController notificationShadeWindowController,
            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
            LockscreenLockIconController lockscreenLockIconController) {
            LockscreenLockIconController lockscreenLockIconController,
            AuthController authController) {
        super();
        mDozeLog = dozeLog;
        mPowerManager = powerManager;
@@ -130,6 +133,7 @@ public final class DozeServiceHost implements DozeHost {
        mNotificationShadeWindowController = notificationShadeWindowController;
        mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
        mLockscreenLockIconController = lockscreenLockIconController;
        mAuthController = authController;
    }

    // TODO: we should try to not pass status bar in here if we can avoid it.
@@ -297,6 +301,7 @@ public final class DozeServiceHost implements DozeHost {
    @Override
    public void dozeTimeTick() {
        mNotificationPanel.dozeTimeTick();
        mAuthController.dozeTimeTick();
        if (mAmbientIndicationContainer instanceof DozeReceiver) {
            ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
        }
Loading