diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 122fcb21a9f43..765a9422585a9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1036,6 +1036,11 @@
15dp
+
+ 8dp
+ 8dp
+
8dp
0dp
48dp
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index ade106fb2223b..3cd4fca0e8771 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -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;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index fdd3b2603a893..82fb80892ab16 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -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 {
- FileWriter fw = new FileWriter(mHbmPath);
- fw.write(mHbmEnableCommand);
- fw.close();
+ if (mHbmSupported) {
+ FileWriter fw = new FileWriter(mHbmPath);
+ fw.write(mHbmEnableCommand);
+ fw.close();
+ }
mFingerprintManager.onFingerDown(x, y, minor, major);
} catch (IOException e) {
mView.hideScrimAndDot();
@@ -246,13 +260,15 @@ class UdfpsController {
mFingerprintManager.onFingerUp();
// Hiding the scrim before disabling HBM results in less noticeable flicker.
mView.hideScrimAndDot();
- try {
- FileWriter fw = new FileWriter(mHbmPath);
- fw.write(mHbmDisableCommand);
- fw.close();
- } catch (IOException e) {
- mView.showScrimAndDot();
- Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage());
+ if (mHbmSupported) {
+ try {
+ FileWriter fw = new FileWriter(mHbmPath);
+ fw.write(mHbmDisableCommand);
+ fw.close();
+ } catch (IOException e) {
+ mView.showScrimAndDot();
+ Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 69883eaa76a7c..36353fa969560 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -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) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index de74d4e04921a..5aca0dfd677ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -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();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index d4a94c5b9e66c..c8566c599108e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -54,6 +54,7 @@ import android.testing.TestableLooper.RunWithLooper;
import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -103,8 +104,8 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
- mAuthController = new TestableAuthController(
- context, mock(CommandQueue.class), new MockInjector());
+ mAuthController = new TestableAuthController(context, mock(CommandQueue.class),
+ mock(StatusBarStateController.class), new MockInjector());
mAuthController.start();
}
@@ -502,8 +503,9 @@ public class AuthControllerTest extends SysuiTestCase {
private int mBuildCount = 0;
private PromptInfo mLastBiometricPromptInfo;
- TestableAuthController(Context context, CommandQueue commandQueue, Injector injector) {
- super(context, commandQueue, injector);
+ TestableAuthController(Context context, CommandQueue commandQueue,
+ StatusBarStateController statusBarStateController, Injector injector) {
+ super(context, commandQueue, statusBarStateController, injector);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index a5f4e51ea13c7..713a7c92e1cfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -36,6 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
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.keyguard.KeyguardViewMediator;
@@ -90,6 +91,7 @@ public class DozeServiceHostTest extends SysuiTestCase {
@Mock private View mAmbientIndicationContainer;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private LockscreenLockIconController mLockscreenLockIconController;
+ @Mock private AuthController mAuthController;
@Before
public void setup() {
@@ -100,7 +102,7 @@ public class DozeServiceHostTest extends SysuiTestCase {
mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
mKeyguardUpdateMonitor, mVisualStabilityManager, mPulseExpansionHandler,
mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
- mLockscreenLockIconController);
+ mLockscreenLockIconController, mAuthController);
mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController,
mStatusBarKeyguardViewManager, mNotificationShadeWindowViewController,