Skip to content

Commit 205fe6d

Browse files
ArianK16aralph950412
authored andcommitted
udfps: Restore illumination dot for global hbm
UdfpsSurfaceView.java is imported from android-12.1.0_r22 Change-Id: I4a4e85a7437a9a444a4f952fd62e4fe12f56ce5a
1 parent f4d99d8 commit 205fe6d

5 files changed

Lines changed: 218 additions & 4 deletions

File tree

packages/SystemUI/res/layout/udfps_touch_overlay.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@
1818
android:id="@+id/udfps_touch_overlay"
1919
android:layout_width="match_parent"
2020
android:layout_height="match_parent">
21+
<com.android.systemui.biometrics.UdfpsSurfaceView
22+
android:id="@+id/hbm_view"
23+
android:layout_width="match_parent"
24+
android:layout_height="match_parent"
25+
android:visibility="invisible"/>
2126
</com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay>

packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
8383
import com.android.systemui.biometrics.udfps.TouchProcessor;
8484
import com.android.systemui.biometrics.udfps.TouchProcessorResult;
85+
import com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay;
8586
import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayViewModel;
8687
import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel;
8788
import com.android.systemui.biometrics.ui.viewmodel.PromptUdfpsTouchOverlayViewModel;
@@ -898,8 +899,9 @@ private void unconfigureDisplay(View view) {
898899
if (!isOptical()) {
899900
return;
900901
}
901-
if (mUdfpsDisplayMode != null) {
902-
mUdfpsDisplayMode.disable(null);
902+
UdfpsTouchOverlay udfpsView = (UdfpsTouchOverlay) view;
903+
if (udfpsView.isDisplayConfigured()) {
904+
udfpsView.unconfigureDisplay();
903905
}
904906
}
905907

@@ -1110,7 +1112,7 @@ private void onFingerDown(
11101112
if (mIgnoreRefreshRate) {
11111113
dispatchOnUiReady(requestId);
11121114
} else {
1113-
mUdfpsDisplayMode.enable(() -> dispatchOnUiReady(requestId));
1115+
((UdfpsTouchOverlay) view).configureDisplay(() -> dispatchOnUiReady(requestId));
11141116
}
11151117
}
11161118

packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ constructor(
176176
(inflater.inflate(R.layout.udfps_touch_overlay, null, false)
177177
as UdfpsTouchOverlay)
178178
.apply {
179+
setUdfpsDisplayModeProvider(udfpsDisplayModeProvider)
179180
// This view overlaps the sensor area
180181
// prevent it from being selectable during a11y
181182
if (requestReason.isImportantForAccessibility()) {
@@ -209,6 +210,7 @@ constructor(
209210
udfpsOverlayInteractor = udfpsOverlayInteractor,
210211
)
211212
}
213+
sensorRect = sensorBounds
212214
}
213215

214216
getTouchOverlay()?.apply {
@@ -285,6 +287,12 @@ constructor(
285287
val wasShowing = isShowing
286288
Log.d(TAG, "hideUdfpsControllerOverlay wasShowing=$wasShowing")
287289
udfpsOverlayInteractor.stopSetHandleTouchesForKeyguard()
290+
291+
overlayTouchView?.apply {
292+
if (isDisplayConfigured) {
293+
unconfigureDisplay()
294+
}
295+
}
288296
udfpsDisplayModeProvider.disable(null)
289297
getTouchOverlay()?.apply {
290298
if (this.parent != null) {
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (C) 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.android.systemui.biometrics;
18+
19+
import android.annotation.NonNull;
20+
import android.annotation.Nullable;
21+
import android.content.Context;
22+
import android.graphics.Canvas;
23+
import android.graphics.Paint;
24+
import android.graphics.PixelFormat;
25+
import android.graphics.RectF;
26+
import android.util.AttributeSet;
27+
import android.util.Log;
28+
import android.view.Surface;
29+
import android.view.SurfaceHolder;
30+
import android.view.SurfaceView;
31+
32+
/**
33+
* Surface View for providing the Global High-Brightness Mode (GHBM) illumination for UDFPS.
34+
*/
35+
public class UdfpsSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
36+
private static final String TAG = "UdfpsSurfaceView";
37+
38+
/**
39+
* Notifies {@link UdfpsView} when to enable GHBM illumination.
40+
*/
41+
interface GhbmIlluminationListener {
42+
/**
43+
* @param surface the surface for which GHBM should be enabled.
44+
* @param onDisplayConfigured a runnable that should be run after GHBM is enabled.
45+
*/
46+
void enableGhbm(@NonNull Surface surface, @Nullable Runnable onDisplayConfigured);
47+
}
48+
49+
@NonNull private final SurfaceHolder mHolder;
50+
@NonNull private final Paint mSensorPaint;
51+
52+
@Nullable private GhbmIlluminationListener mGhbmIlluminationListener;
53+
@Nullable private Runnable mOnDisplayConfigured;
54+
boolean mAwaitingSurfaceToStartIllumination;
55+
boolean mHasValidSurface;
56+
57+
public UdfpsSurfaceView(Context context, AttributeSet attrs) {
58+
super(context, attrs);
59+
60+
// Make this SurfaceView draw on top of everything else in this window. This allows us to
61+
// 1) Always show the HBM circle on top of everything else, and
62+
// 2) Properly composite this view with any other animations in the same window no matter
63+
// what contents are added in which order to this view hierarchy.
64+
setZOrderOnTop(true);
65+
66+
mHolder = getHolder();
67+
mHolder.addCallback(this);
68+
mHolder.setFormat(PixelFormat.RGBA_8888);
69+
70+
mSensorPaint = new Paint(0 /* flags */);
71+
mSensorPaint.setAntiAlias(true);
72+
mSensorPaint.setARGB(255, 255, 255, 255);
73+
mSensorPaint.setStyle(Paint.Style.FILL);
74+
}
75+
76+
@Override public void surfaceCreated(SurfaceHolder holder) {
77+
mHasValidSurface = true;
78+
if (mAwaitingSurfaceToStartIllumination) {
79+
doIlluminate(mOnDisplayConfigured);
80+
mOnDisplayConfigured = null;
81+
mAwaitingSurfaceToStartIllumination = false;
82+
}
83+
}
84+
85+
@Override
86+
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
87+
// Unused.
88+
}
89+
90+
@Override public void surfaceDestroyed(SurfaceHolder holder) {
91+
mHasValidSurface = false;
92+
}
93+
94+
public void setGhbmIlluminationListener(@Nullable GhbmIlluminationListener listener) {
95+
mGhbmIlluminationListener = listener;
96+
}
97+
98+
/**
99+
* Note: there is no corresponding method to stop GHBM illumination. It is expected that
100+
* {@link UdfpsView} will hide this view, which would destroy the surface and remove the
101+
* illumination dot.
102+
*/
103+
public void startGhbmIllumination(@Nullable Runnable onDisplayConfigured) {
104+
if (mGhbmIlluminationListener == null) {
105+
Log.e(TAG, "startIllumination | mGhbmIlluminationListener is null");
106+
return;
107+
}
108+
109+
if (mHasValidSurface) {
110+
doIlluminate(onDisplayConfigured);
111+
} else {
112+
mAwaitingSurfaceToStartIllumination = true;
113+
mOnDisplayConfigured = onDisplayConfigured;
114+
}
115+
}
116+
117+
private void doIlluminate(@Nullable Runnable onDisplayConfigured) {
118+
if (mGhbmIlluminationListener == null) {
119+
Log.e(TAG, "doIlluminate | mGhbmIlluminationListener is null");
120+
return;
121+
}
122+
123+
mGhbmIlluminationListener.enableGhbm(mHolder.getSurface(), onDisplayConfigured);
124+
}
125+
126+
/**
127+
* Immediately draws the illumination dot on this SurfaceView's surface.
128+
*/
129+
public void drawIlluminationDot(@NonNull RectF sensorRect) {
130+
if (!mHasValidSurface) {
131+
Log.e(TAG, "drawIlluminationDot | the surface is destroyed or was never created.");
132+
return;
133+
}
134+
Canvas canvas = null;
135+
try {
136+
canvas = mHolder.lockCanvas();
137+
canvas.drawOval(sensorRect, mSensorPaint);
138+
} finally {
139+
// Make sure the surface is never left in a bad state.
140+
if (canvas != null) {
141+
mHolder.unlockCanvasAndPost(canvas);
142+
}
143+
}
144+
}
145+
}

packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,65 @@
1616
package com.android.systemui.biometrics.ui.view
1717

1818
import android.content.Context
19+
import android.graphics.Rect
20+
import android.graphics.RectF
1921
import android.util.AttributeSet
22+
import android.view.Surface
2023
import android.widget.FrameLayout
2124

25+
import com.android.systemui.biometrics.UdfpsDisplayModeProvider
26+
import com.android.systemui.biometrics.UdfpsSurfaceView
27+
import com.android.systemui.res.R
28+
2229
/**
2330
* A translucent (not visible to the user) view that receives touches to send to FingerprintManager
2431
* for fingerprint authentication.
2532
*/
26-
class UdfpsTouchOverlay(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs)
33+
class UdfpsTouchOverlay(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
34+
private var ghbmView: UdfpsSurfaceView? = null
35+
private var udfpsDisplayMode: UdfpsDisplayModeProvider? = null
36+
37+
// sensorRect may be bigger than the sensor. True sensor dimensions are defined in
38+
// overlayParams.sensorBounds
39+
var sensorRect = Rect()
40+
41+
/** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */
42+
var isDisplayConfigured: Boolean = false
43+
private set
44+
45+
override fun onFinishInflate() {
46+
ghbmView = findViewById(R.id.hbm_view)
47+
}
48+
49+
fun setUdfpsDisplayModeProvider(udfpsDisplayModeProvider: UdfpsDisplayModeProvider?) {
50+
udfpsDisplayMode = udfpsDisplayModeProvider
51+
}
52+
53+
fun configureDisplay(onDisplayConfigured: Runnable) {
54+
isDisplayConfigured = true
55+
val gView = ghbmView
56+
if (gView != null) {
57+
gView.setGhbmIlluminationListener(this::doIlluminate)
58+
gView.visibility = VISIBLE
59+
gView.startGhbmIllumination(onDisplayConfigured)
60+
} else {
61+
doIlluminate(null /* surface */, onDisplayConfigured)
62+
}
63+
}
64+
65+
private fun doIlluminate(surface: Surface?, onDisplayConfigured: Runnable?) {
66+
udfpsDisplayMode?.enable {
67+
onDisplayConfigured?.run()
68+
ghbmView?.drawIlluminationDot(RectF(sensorRect))
69+
}
70+
}
71+
72+
fun unconfigureDisplay() {
73+
isDisplayConfigured = false
74+
ghbmView?.let { view ->
75+
view.setGhbmIlluminationListener(null)
76+
view.visibility = INVISIBLE
77+
}
78+
udfpsDisplayMode?.disable(null /* onDisabled */)
79+
}
80+
}

0 commit comments

Comments
 (0)