Loading packages/SystemUI/compose/core/src/com/android/compose/gesture/GesturesDisabled.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.compose.gesture import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.pointerInput /** Disable gestures to this node (and descendants). */ fun Modifier.gesturesDisabled(): Modifier { return pointerInput(Unit) { awaitPointerEventScope { // we should wait for all new pointer events while (true) { awaitPointerEvent(pass = PointerEventPass.Initial) .changes .forEach(PointerInputChange::consume) } } } } packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +5 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.animateContentFloatAsState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState import com.android.compose.animation.scene.transitions import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.thenIf Loading Loading @@ -162,7 +163,10 @@ constructor( viewModel = viewModel, headerViewModel = viewModel.qsContainerViewModel.shadeHeaderViewModel, notificationsPlaceholderViewModel = notificationsPlaceholderViewModel, modifier = modifier.graphicsLayer { alpha = contentAlpha }, modifier = modifier .graphicsLayer { alpha = contentAlpha } .thenIf(brightnessMirrorShowing) { Modifier.gesturesDisabled() }, shadeSession = shadeSession, jankMonitor = jankMonitor, ) Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +8 −2 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.animation.scene.mechanics.TileRevealFlag import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.thenIf import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer Loading Loading @@ -164,7 +165,12 @@ constructor( LaunchedEffectWithLifecycle(key1 = Unit) { contentViewModel.detectShadeModeChanges() } Box(modifier = modifier.graphicsLayer { alpha = contentAlphaFromBrightnessMirror }) { Box( modifier = modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { OverlayShade( panelElement = QuickSettingsShade.Elements.Panel, alignmentOnWideScreens = Alignment.TopEnd, Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +9 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.animateContentFloatAsState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState import com.android.compose.animation.scene.transitions import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.padding import com.android.compose.modifiers.thenIf Loading Loading @@ -103,6 +104,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati import dagger.Lazy import javax.inject.Inject import kotlin.math.roundToInt import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow object Shade { Loading Loading @@ -431,7 +433,13 @@ private fun ContentScope.SplitShade( } } Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = contentAlpha }) { Box( modifier = modifier .fillMaxSize() .graphicsLayer { alpha = contentAlpha } .thenIf(brightnessMirrorShowing) { Modifier.gesturesDisabled() } ) { ShadePanelScrim(viewModel.isTransparencyEnabled) Column(modifier = Modifier.fillMaxSize()) { Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelTest.kt +16 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds Loading Loading @@ -136,4 +139,17 @@ class NotificationScrollViewModelTest : SysuiTestCase() { disposable.dispose() } @Test fun noDualShade_brightnessMirrorShowing_notInteractive() = kosmos.runTest { disableDualShade() val interactive by collectLastValue(underTest.interactive) brightnessMirrorShowingInteractor.setMirrorShowing(false) assertThat(interactive).isTrue() brightnessMirrorShowingInteractor.setMirrorShowing(true) assertThat(interactive).isFalse() } } Loading
packages/SystemUI/compose/core/src/com/android/compose/gesture/GesturesDisabled.kt 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.compose.gesture import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.pointerInput /** Disable gestures to this node (and descendants). */ fun Modifier.gesturesDisabled(): Modifier { return pointerInput(Unit) { awaitPointerEventScope { // we should wait for all new pointer events while (true) { awaitPointerEvent(pass = PointerEventPass.Initial) .changes .forEach(PointerInputChange::consume) } } } }
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +5 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.animateContentFloatAsState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState import com.android.compose.animation.scene.transitions import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.thenIf Loading Loading @@ -162,7 +163,10 @@ constructor( viewModel = viewModel, headerViewModel = viewModel.qsContainerViewModel.shadeHeaderViewModel, notificationsPlaceholderViewModel = notificationsPlaceholderViewModel, modifier = modifier.graphicsLayer { alpha = contentAlpha }, modifier = modifier .graphicsLayer { alpha = contentAlpha } .thenIf(brightnessMirrorShowing) { Modifier.gesturesDisabled() }, shadeSession = shadeSession, jankMonitor = jankMonitor, ) Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +8 −2 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.animation.scene.mechanics.TileRevealFlag import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.DisposableEffectWithLifecycle import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.thenIf import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer Loading Loading @@ -164,7 +165,12 @@ constructor( LaunchedEffectWithLifecycle(key1 = Unit) { contentViewModel.detectShadeModeChanges() } Box(modifier = modifier.graphicsLayer { alpha = contentAlphaFromBrightnessMirror }) { Box( modifier = modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { OverlayShade( panelElement = QuickSettingsShade.Elements.Panel, alignmentOnWideScreens = Alignment.TopEnd, Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +9 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.animateContentFloatAsState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState import com.android.compose.animation.scene.transitions import com.android.compose.gesture.gesturesDisabled import com.android.compose.lifecycle.LaunchedEffectWithLifecycle import com.android.compose.modifiers.padding import com.android.compose.modifiers.thenIf Loading Loading @@ -103,6 +104,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati import dagger.Lazy import javax.inject.Inject import kotlin.math.roundToInt import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow object Shade { Loading Loading @@ -431,7 +433,13 @@ private fun ContentScope.SplitShade( } } Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = contentAlpha }) { Box( modifier = modifier .fillMaxSize() .graphicsLayer { alpha = contentAlpha } .thenIf(brightnessMirrorShowing) { Modifier.gesturesDisabled() } ) { ShadePanelScrim(viewModel.isTransparencyEnabled) Column(modifier = Modifier.fillMaxSize()) { Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModelTest.kt +16 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds Loading Loading @@ -136,4 +139,17 @@ class NotificationScrollViewModelTest : SysuiTestCase() { disposable.dispose() } @Test fun noDualShade_brightnessMirrorShowing_notInteractive() = kosmos.runTest { disableDualShade() val interactive by collectLastValue(underTest.interactive) brightnessMirrorShowingInteractor.setMirrorShowing(false) assertThat(interactive).isTrue() brightnessMirrorShowingInteractor.setMirrorShowing(true) assertThat(interactive).isFalse() } }