• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.deviceentry.ui.viewmodel
18 
19 import android.graphics.Point
20 import android.view.MotionEvent
21 import android.view.View
22 import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
23 import com.android.systemui.biometrics.UdfpsUtils
24 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
25 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
26 import kotlinx.coroutines.flow.Flow
27 import kotlinx.coroutines.flow.StateFlow
28 import kotlinx.coroutines.flow.flatMapLatest
29 import kotlinx.coroutines.flow.flowOf
30 
31 /** Models the UI state for the UDFPS accessibility overlay */
32 abstract class UdfpsAccessibilityOverlayViewModel(
33     udfpsOverlayInteractor: UdfpsOverlayInteractor,
34     accessibilityInteractor: AccessibilityInteractor,
35 ) {
36     private val udfpsUtils = UdfpsUtils()
37     private val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> =
38         udfpsOverlayInteractor.udfpsOverlayParams
39 
40     val visible: Flow<Boolean> =
41         accessibilityInteractor.isTouchExplorationEnabled.flatMapLatest { touchExplorationEnabled ->
42             if (touchExplorationEnabled) {
43                 isVisibleWhenTouchExplorationEnabled()
44             } else {
45                 flowOf(false)
46             }
47         }
48 
49     abstract fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean>
50 
51     /** Give directional feedback to help the user authenticate with UDFPS. */
52     fun onHoverEvent(v: View, event: MotionEvent): Boolean {
53         val overlayParams = udfpsOverlayParams.value
54         val scaledTouch: Point =
55             udfpsUtils.getTouchInNativeCoordinates(
56                 event.getPointerId(0),
57                 event,
58                 overlayParams, /* rotateToPortrait */
59                 false
60             )
61 
62         if (
63             !udfpsUtils.isWithinSensorArea(
64                 event.getPointerId(0),
65                 event,
66                 overlayParams,
67                 /* rotateTouchToPortrait */ false
68             )
69         ) {
70             // view only receives motionEvents when [visible] which requires touchExplorationEnabled
71             val announceStr =
72                 udfpsUtils.onTouchOutsideOfSensorArea(
73                     /* touchExplorationEnabled */ true,
74                     v.context,
75                     scaledTouch.x,
76                     scaledTouch.y,
77                     overlayParams,
78                     /* touchRotatedToPortrait */ false
79                 )
80             if (announceStr != null) {
81                 v.announceForAccessibility(announceStr)
82             }
83         }
84         // always let the motion events go through to underlying views
85         return false
86     }
87 }
88