1 /*
<lambda>null2  * Copyright (C) 2022 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.shade
18 
19 import android.graphics.Point
20 import android.hardware.display.AmbientDisplayConfiguration
21 import android.os.PowerManager
22 import android.provider.Settings
23 import android.view.GestureDetector
24 import android.view.MotionEvent
25 import com.android.systemui.Dumpable
26 import com.android.systemui.dagger.SysUISingleton
27 import com.android.systemui.dock.DockManager
28 import com.android.systemui.dump.DumpManager
29 import com.android.systemui.keyguard.domain.interactor.DozeInteractor
30 import com.android.systemui.plugins.FalsingManager
31 import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
32 import com.android.systemui.plugins.statusbar.StatusBarStateController
33 import com.android.systemui.power.domain.interactor.PowerInteractor
34 import com.android.systemui.settings.UserTracker
35 import com.android.systemui.tuner.TunerService
36 import com.android.systemui.tuner.TunerService.Tunable
37 import java.io.PrintWriter
38 import javax.inject.Inject
39 
40 /**
41  * If tap and/or double tap to wake is enabled, this gestureListener will wake the display on
42  * tap/double tap when the device is pulsing (AoD2) or transitioning to AoD. Taps are gated by the
43  * proximity sensor and falsing manager.
44  *
45  * Touches go through the [NotificationShadeWindowViewController] when the device is dozing but the
46  * screen is still ON and not in the true AoD display state. When the device is in the true AoD
47  * display state, wake-ups are handled by [com.android.systemui.doze.DozeSensors].
48  */
49 @SysUISingleton
50 class PulsingGestureListener @Inject constructor(
51         private val falsingManager: FalsingManager,
52         private val dockManager: DockManager,
53         private val powerInteractor: PowerInteractor,
54         private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
55         private val statusBarStateController: StatusBarStateController,
56         private val shadeLogger: ShadeLogger,
57         private val dozeInteractor: DozeInteractor,
58         userTracker: UserTracker,
59         tunerService: TunerService,
60         dumpManager: DumpManager
61 ) : GestureDetector.SimpleOnGestureListener(), Dumpable {
62     private var doubleTapEnabled = false
63     private var singleTapEnabled = false
64 
65     init {
66         val tunable = Tunable { key: String?, _: String? ->
67             when (key) {
68                 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE ->
69                     doubleTapEnabled = ambientDisplayConfiguration.doubleTapGestureEnabled(
70                             userTracker.userId)
71                 Settings.Secure.DOZE_TAP_SCREEN_GESTURE ->
72                     singleTapEnabled = ambientDisplayConfiguration.tapGestureEnabled(
73                             userTracker.userId)
74             }
75         }
76         tunerService.addTunable(tunable,
77                 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
78                 Settings.Secure.DOZE_TAP_SCREEN_GESTURE)
79 
80         dumpManager.registerDumpable(this)
81     }
82 
83     override fun onSingleTapUp(e: MotionEvent): Boolean {
84         val isNotDocked = !dockManager.isDocked
85         shadeLogger.logSingleTapUp(statusBarStateController.isDozing, singleTapEnabled, isNotDocked)
86         if (statusBarStateController.isDozing && singleTapEnabled && isNotDocked) {
87             val proximityIsNotNear = !falsingManager.isProximityNear
88             val isNotAFalseTap = !falsingManager.isFalseTap(LOW_PENALTY)
89             shadeLogger.logSingleTapUpFalsingState(proximityIsNotNear, isNotAFalseTap)
90             if (proximityIsNotNear && isNotAFalseTap) {
91                 shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing")
92                 dozeInteractor.setLastTapToWakePosition(Point(e.x.toInt(), e.y.toInt()))
93                 powerInteractor.wakeUpIfDozing("PULSING_SINGLE_TAP", PowerManager.WAKE_REASON_TAP)
94             }
95             return true
96         }
97         shadeLogger.d("onSingleTapUp event ignored")
98         return false
99     }
100 
101     /**
102      * Receives [MotionEvent.ACTION_DOWN], [MotionEvent.ACTION_MOVE], and [MotionEvent.ACTION_UP]
103      * motion events for a double tap.
104      */
105     override fun onDoubleTapEvent(e: MotionEvent): Boolean {
106         // React to the [MotionEvent.ACTION_UP] event after double tap is detected. Falsing
107         // checks MUST be on the ACTION_UP event.
108         if (e.actionMasked == MotionEvent.ACTION_UP &&
109                 statusBarStateController.isDozing &&
110                 (doubleTapEnabled || singleTapEnabled) &&
111                 !falsingManager.isProximityNear &&
112                 !falsingManager.isFalseDoubleTap
113         ) {
114             powerInteractor.wakeUpIfDozing("PULSING_DOUBLE_TAP", PowerManager.WAKE_REASON_TAP)
115             return true
116         }
117         return false
118     }
119 
120     override fun dump(pw: PrintWriter, args: Array<out String>) {
121         pw.println("singleTapEnabled=$singleTapEnabled")
122         pw.println("doubleTapEnabled=$doubleTapEnabled")
123         pw.println("isDocked=${dockManager.isDocked}")
124         pw.println("isProxCovered=${falsingManager.isProximityNear}")
125     }
126 }
127