diff options
| author | 2024-06-26 16:32:57 -0700 | |
|---|---|---|
| committer | 2024-06-26 19:51:08 -0700 | |
| commit | 69ccc07451ce0634e4c3e9de61da1d02a23b6bbf (patch) | |
| tree | 11c3f778eeb951be66e6f2f7a94ea77761a7d8f7 | |
| parent | 6656e1db5c7cf4eb66b277c362c39719a85cd7e3 (diff) | |
[flexiglass] Wake up from AOD when lockscreen tapped.
During the first ~4 seconds after entering AOD, tapping the lockscreen
should wake up the device and exit AOD. This wasn't happening in
Flexiglass. This CL makes it work.
The PulsingGestureListener is responsible for translating taps and
double taps into the proper wakefulness state changes. This CL hooks it
up to the pre-existing LockscreenLongPress (which is renamed to a more
generic name in the follow-up CL).
Bug: 344879669
Test: manually verified that tapping or double tapping on the AOD
lockscreen during the first 4 seconds properly wakes up the device and
exits AOD.
Flag: com.android.systemui.scene_container
Change-Id: I44352c788e841a475f5b31a460c69cdcda91685f
10 files changed, 161 insertions, 33 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt index 4555f13a1a2c..cc64a7dfce10 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt @@ -19,9 +19,10 @@ package com.android.systemui.keyguard.ui.composable import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.gestures.awaitFirstDown +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.indication import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -33,10 +34,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect import androidx.compose.ui.input.pointer.pointerInput import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.systemui.communal.ui.compose.extensions.detectLongPressGesture import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel /** Container for lockscreen content that handles long-press to bring up the settings menu. */ @Composable +// TODO(b/344879669): now that it's more generic than long-press, rename it. fun LockscreenLongPress( viewModel: KeyguardLongPressViewModel, modifier: Modifier = Modifier, @@ -50,14 +53,17 @@ fun LockscreenLongPress( Box( modifier = modifier - .combinedClickable( - enabled = isEnabled, - onLongClick = viewModel::onLongPress, - onClick = {}, - interactionSource = interactionSource, - // Passing null for the indication removes the ripple effect. - indication = null, - ) + .pointerInput(isEnabled) { + if (isEnabled) { + detectLongPressGesture { viewModel.onLongPress() } + } + } + .pointerInput(Unit) { + detectTapGestures( + onTap = { viewModel.onClick(it.x, it.y) }, + onDoubleTap = { viewModel.onDoubleClick() }, + ) + } .pointerInput(settingsMenuBounds) { awaitEachGesture { val pointerInputChange = awaitFirstDown() @@ -65,7 +71,9 @@ fun LockscreenLongPress( viewModel.onTouchedOutside() } } - }, + } + // Passing null for the indication removes the ripple effect. + .indication(interactionSource, null) ) { content(setSettingsMenuBounds) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt index 9d34903d544d..da3de3220267 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.testScope import com.android.systemui.res.R +import com.android.systemui.shade.pulsingGestureListener import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock @@ -300,7 +301,8 @@ class KeyguardLongPressInteractorTest : SysuiTestCase() { set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, isOpenWppDirectlyEnabled) }, broadcastDispatcher = fakeBroadcastDispatcher, - accessibilityManager = kosmos.accessibilityManagerWrapper + accessibilityManager = kosmos.accessibilityManagerWrapper, + pulsingGestureListener = kosmos.pulsingGestureListener, ) setUpState() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt index bb6215a8b215..5f646a7ce547 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt @@ -32,6 +32,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.res.R +import com.android.systemui.shade.PulsingGestureListener import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -54,6 +55,7 @@ import kotlinx.coroutines.launch /** Business logic for use-cases related to the keyguard long-press feature. */ @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton +// TODO(b/344879669): now that it's more generic than long-press, rename it. class KeyguardLongPressInteractor @Inject constructor( @@ -65,6 +67,7 @@ constructor( private val featureFlags: FeatureFlags, broadcastDispatcher: BroadcastDispatcher, private val accessibilityManager: AccessibilityManagerWrapper, + private val pulsingGestureListener: PulsingGestureListener, ) { /** Whether the long-press handling feature should be enabled. */ val isLongPressHandlingEnabled: StateFlow<Boolean> = @@ -166,6 +169,16 @@ constructor( _shouldOpenSettings.value = false } + /** Notifies that the lockscreen has been clicked at position [x], [y]. */ + fun onClick(x: Float, y: Float) { + pulsingGestureListener.onSingleTapUp(x, y) + } + + /** Notifies that the lockscreen has been double clicked. */ + fun onDoubleClick() { + pulsingGestureListener.onDoubleTapEvent() + } + private fun showSettings() { _shouldOpenSettings.value = true } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt index c73931a12455..90fef6fb64e0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.flow.Flow /** Models UI state to support the lock screen long-press feature. */ @SysUISingleton +// TODO(b/344879669): now that it's more generic than long-press, rename it. class KeyguardLongPressViewModel @Inject constructor( @@ -45,4 +46,14 @@ constructor( fun onTouchedOutside() { interactor.onTouchedOutside() } + + /** Notifies that the lockscreen has been clicked at position [x], [y]. */ + fun onClick(x: Float, y: Float) { + interactor.onClick(x, y) + } + + /** Notifies that the lockscreen has been double clicked. */ + fun onDoubleClick() { + interactor.onDoubleClick() + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index e41f99b99e35..9cddf86a40e6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -369,7 +369,9 @@ public class NotificationShadeWindowViewController implements Dumpable { } mFalsingCollector.onTouchEvent(ev); - mPulsingWakeupGestureHandler.onTouchEvent(ev); + if (!SceneContainerFlag.isEnabled()) { + mPulsingWakeupGestureHandler.onTouchEvent(ev); + } if (!SceneContainerFlag.isEnabled() && mGlanceableHubContainerController.onTouchEvent(ev)) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt index fe4832f0895b..062327dc2acf 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt @@ -47,17 +47,19 @@ import javax.inject.Inject * display state, wake-ups are handled by [com.android.systemui.doze.DozeSensors]. */ @SysUISingleton -class PulsingGestureListener @Inject constructor( - private val falsingManager: FalsingManager, - private val dockManager: DockManager, - private val powerInteractor: PowerInteractor, - private val ambientDisplayConfiguration: AmbientDisplayConfiguration, - private val statusBarStateController: StatusBarStateController, - private val shadeLogger: ShadeLogger, - private val dozeInteractor: DozeInteractor, - userTracker: UserTracker, - tunerService: TunerService, - dumpManager: DumpManager +class PulsingGestureListener +@Inject +constructor( + private val falsingManager: FalsingManager, + private val dockManager: DockManager, + private val powerInteractor: PowerInteractor, + private val ambientDisplayConfiguration: AmbientDisplayConfiguration, + private val statusBarStateController: StatusBarStateController, + private val shadeLogger: ShadeLogger, + private val dozeInteractor: DozeInteractor, + userTracker: UserTracker, + tunerService: TunerService, + dumpManager: DumpManager ) : GestureDetector.SimpleOnGestureListener(), Dumpable { private var doubleTapEnabled = false private var singleTapEnabled = false @@ -66,21 +68,27 @@ class PulsingGestureListener @Inject constructor( val tunable = Tunable { key: String?, _: String? -> when (key) { Settings.Secure.DOZE_DOUBLE_TAP_GESTURE -> - doubleTapEnabled = ambientDisplayConfiguration.doubleTapGestureEnabled( - userTracker.userId) + doubleTapEnabled = + ambientDisplayConfiguration.doubleTapGestureEnabled(userTracker.userId) Settings.Secure.DOZE_TAP_SCREEN_GESTURE -> - singleTapEnabled = ambientDisplayConfiguration.tapGestureEnabled( - userTracker.userId) + singleTapEnabled = + ambientDisplayConfiguration.tapGestureEnabled(userTracker.userId) } } - tunerService.addTunable(tunable, - Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, - Settings.Secure.DOZE_TAP_SCREEN_GESTURE) + tunerService.addTunable( + tunable, + Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, + Settings.Secure.DOZE_TAP_SCREEN_GESTURE + ) dumpManager.registerDumpable(this) } override fun onSingleTapUp(e: MotionEvent): Boolean { + return onSingleTapUp(e.x, e.y) + } + + fun onSingleTapUp(x: Float, y: Float): Boolean { val isNotDocked = !dockManager.isDocked shadeLogger.logSingleTapUp(statusBarStateController.isDozing, singleTapEnabled, isNotDocked) if (statusBarStateController.isDozing && singleTapEnabled && isNotDocked) { @@ -89,11 +97,13 @@ class PulsingGestureListener @Inject constructor( shadeLogger.logSingleTapUpFalsingState(proximityIsNotNear, isNotAFalseTap) if (proximityIsNotNear && isNotAFalseTap) { shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing") - dozeInteractor.setLastTapToWakePosition(Point(e.x.toInt(), e.y.toInt())) + dozeInteractor.setLastTapToWakePosition(Point(x.toInt(), y.toInt())) powerInteractor.wakeUpIfDozing("PULSING_SINGLE_TAP", PowerManager.WAKE_REASON_TAP) } + return true } + shadeLogger.d("onSingleTapUp event ignored") return false } @@ -103,10 +113,18 @@ class PulsingGestureListener @Inject constructor( * motion events for a double tap. */ override fun onDoubleTapEvent(e: MotionEvent): Boolean { + if (e.actionMasked != MotionEvent.ACTION_UP) { + return false + } + + return onDoubleTapEvent() + } + + fun onDoubleTapEvent(): Boolean { // React to the [MotionEvent.ACTION_UP] event after double tap is detected. Falsing // checks MUST be on the ACTION_UP event. - if (e.actionMasked == MotionEvent.ACTION_UP && - statusBarStateController.isDozing && + if ( + statusBarStateController.isDozing && (doubleTapEnabled || singleTapEnabled) && !falsingManager.isProximityNear && !falsingManager.isFalseDoubleTap @@ -114,6 +132,7 @@ class PulsingGestureListener @Inject constructor( powerInteractor.wakeUpIfDozing("PULSING_DOUBLE_TAP", PowerManager.WAKE_REASON_TAP) return true } + return false } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index bdc5fc34158f..68a6e777e97d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -58,6 +58,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.shade.pulsingGestureListener import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.statusbar.policy.KeyguardStateController @@ -221,6 +222,7 @@ class KeyguardBottomAreaViewModelTest(flags: FlagsParameterization) : SysuiTestC featureFlags = featureFlags, broadcastDispatcher = broadcastDispatcher, accessibilityManager = accessibilityManager, + pulsingGestureListener = kosmos.pulsingGestureListener, ) underTest = KeyguardBottomAreaViewModel( diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/AmbientDisplayConfigurationKosmos.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/AmbientDisplayConfigurationKosmos.kt new file mode 100644 index 000000000000..3f3c30f0faec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/hardware/display/AmbientDisplayConfigurationKosmos.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.display + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.ambientDisplayConfiguration by Fixture { + FakeAmbientDisplayConfiguration(applicationContext) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt index c06f833c9e96..cd0d554e6b1d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.shade.pulsingGestureListener val Kosmos.keyguardLongPressInteractor by Kosmos.Fixture { @@ -36,5 +37,6 @@ val Kosmos.keyguardLongPressInteractor by featureFlags = featureFlagsClassic, broadcastDispatcher = broadcastDispatcher, accessibilityManager = accessibilityManagerWrapper, + pulsingGestureListener = pulsingGestureListener, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/PulsingGestureListenerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/PulsingGestureListenerKosmos.kt new file mode 100644 index 000000000000..4fc22289585f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/PulsingGestureListenerKosmos.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import android.hardware.display.ambientDisplayConfiguration +import com.android.systemui.classifier.falsingManager +import com.android.systemui.dock.dockManager +import com.android.systemui.dump.dumpManager +import com.android.systemui.keyguard.domain.interactor.dozeInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.plugins.statusbar.statusBarStateController +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.settings.userTracker +import com.android.systemui.util.mockito.mock + +val Kosmos.pulsingGestureListener by Fixture { + PulsingGestureListener( + falsingManager = falsingManager, + dockManager = dockManager, + powerInteractor = powerInteractor, + ambientDisplayConfiguration = ambientDisplayConfiguration, + statusBarStateController = statusBarStateController, + shadeLogger = mock(), + dozeInteractor = dozeInteractor, + userTracker = userTracker, + tunerService = mock(), + dumpManager = dumpManager, + ) +} |