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 51 @Inject 52 constructor( 53 private val falsingManager: FalsingManager, 54 private val dockManager: DockManager, 55 private val powerInteractor: PowerInteractor, 56 private val ambientDisplayConfiguration: AmbientDisplayConfiguration, 57 private val statusBarStateController: StatusBarStateController, 58 private val shadeLogger: ShadeLogger, 59 private val dozeInteractor: DozeInteractor, 60 userTracker: UserTracker, 61 tunerService: TunerService, 62 dumpManager: DumpManager 63 ) : GestureDetector.SimpleOnGestureListener(), Dumpable { 64 private var doubleTapEnabled = false 65 private var singleTapEnabled = false 66 67 init { 68 val tunable = Tunable { key: String?, _: String? -> 69 when (key) { 70 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE -> 71 doubleTapEnabled = 72 ambientDisplayConfiguration.doubleTapGestureEnabled(userTracker.userId) 73 Settings.Secure.DOZE_TAP_SCREEN_GESTURE -> 74 singleTapEnabled = 75 ambientDisplayConfiguration.tapGestureEnabled(userTracker.userId) 76 } 77 } 78 tunerService.addTunable( 79 tunable, 80 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 81 Settings.Secure.DOZE_TAP_SCREEN_GESTURE 82 ) 83 84 dumpManager.registerDumpable(this) 85 } 86 87 override fun onSingleTapUp(e: MotionEvent): Boolean { 88 return onSingleTapUp(e.x, e.y) 89 } 90 91 fun onSingleTapUp(x: Float, y: Float): Boolean { 92 val isNotDocked = !dockManager.isDocked 93 shadeLogger.logSingleTapUp(statusBarStateController.isDozing, singleTapEnabled, isNotDocked) 94 if (statusBarStateController.isDozing && singleTapEnabled && isNotDocked) { 95 val proximityIsNotNear = !falsingManager.isProximityNear 96 val isNotAFalseTap = !falsingManager.isFalseTap(LOW_PENALTY) 97 shadeLogger.logSingleTapUpFalsingState(proximityIsNotNear, isNotAFalseTap) 98 if (proximityIsNotNear && isNotAFalseTap) { 99 shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing") 100 dozeInteractor.setLastTapToWakePosition(Point(x.toInt(), y.toInt())) 101 powerInteractor.wakeUpIfDozing("PULSING_SINGLE_TAP", PowerManager.WAKE_REASON_TAP) 102 } 103 104 return true 105 } 106 107 shadeLogger.d("onSingleTapUp event ignored") 108 return false 109 } 110 111 /** 112 * Receives [MotionEvent.ACTION_DOWN], [MotionEvent.ACTION_MOVE], and [MotionEvent.ACTION_UP] 113 * motion events for a double tap. 114 */ 115 override fun onDoubleTapEvent(e: MotionEvent): Boolean { 116 if (e.actionMasked != MotionEvent.ACTION_UP) { 117 return false 118 } 119 120 return onDoubleTapEvent() 121 } 122 123 fun onDoubleTapEvent(): Boolean { 124 // React to the [MotionEvent.ACTION_UP] event after double tap is detected. Falsing 125 // checks MUST be on the ACTION_UP event. 126 if ( 127 statusBarStateController.isDozing && 128 (doubleTapEnabled || singleTapEnabled) && 129 !falsingManager.isProximityNear && 130 !falsingManager.isFalseDoubleTap 131 ) { 132 powerInteractor.wakeUpIfDozing("PULSING_DOUBLE_TAP", PowerManager.WAKE_REASON_TAP) 133 return true 134 } 135 136 return false 137 } 138 139 override fun dump(pw: PrintWriter, args: Array<out String>) { 140 pw.println("singleTapEnabled=$singleTapEnabled") 141 pw.println("doubleTapEnabled=$doubleTapEnabled") 142 pw.println("isDocked=${dockManager.isDocked}") 143 pw.println("isProxCovered=${falsingManager.isProximityNear}") 144 } 145 } 146