diff options
13 files changed, 215 insertions, 20 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index 5e0761063af2..32986649388d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -92,6 +92,14 @@ private fun Scene( onSceneChanged: (SceneModel) -> Unit, modifier: Modifier = Modifier, ) { + val destinationScenes: Map<UserAction, SceneModel> by + scene.destinationScenes(containerName).collectAsState() + val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)] + val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)] + val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)] + val swipeDownDestinationScene = destinationScenes[UserAction.Swipe(Direction.DOWN)] + val backDestinationScene = destinationScenes[UserAction.Back] + // TODO(b/280880714): replace with the real UI and make sure to call onTransitionProgress. Box(modifier) { Column( @@ -103,14 +111,6 @@ private fun Scene( modifier = Modifier, ) - val destinationScenes: Map<UserAction, SceneModel> by - scene.destinationScenes(containerName).collectAsState() - val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)] - val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)] - val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)] - val swipeDownDestinationScene = destinationScenes[UserAction.Swipe(Direction.DOWN)] - val backDestinationScene = destinationScenes[UserAction.Back] - Row( horizontalArrangement = Arrangement.spacedBy(8.dp), ) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index a737a8bca585..bf40a2d0ad51 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -84,6 +84,8 @@ import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -94,6 +96,8 @@ import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; +import com.android.systemui.scene.domain.interactor.SceneInteractor; +import com.android.systemui.scene.shared.model.SceneContainerNames; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeViewController; @@ -120,6 +124,7 @@ import java.util.concurrent.Executor; import java.util.function.Supplier; import javax.inject.Inject; +import javax.inject.Provider; /** * Class to send information from overview to launcher with a binder. @@ -139,6 +144,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; private final Context mContext; + private final FeatureFlags mFeatureFlags; private final Executor mMainExecutor; private final ShellInterface mShellInterface; private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; @@ -147,6 +153,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final Handler mHandler; private final Lazy<NavigationBarController> mNavBarControllerLazy; private final NotificationShadeWindowController mStatusBarWinController; + private final Provider<SceneInteractor> mSceneInteractor; + private final Runnable mConnectionRunnable = () -> internalConnectToCurrentUser("runnable: startConnectionToCurrentUser"); private final ComponentName mRecentsComponentName; @@ -209,17 +217,28 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mInputFocusTransferStarted = true; mInputFocusTransferStartY = event.getY(); mInputFocusTransferStartMillis = event.getEventTime(); - centralSurfaces.onInputFocusTransfer( - mInputFocusTransferStarted, false /* cancel */, - 0 /* velocity */); + + // If scene framework is enabled, set the scene container window to + // visible and let the touch "slip" into that window. + if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) { + mSceneInteractor.get().setVisible( + SceneContainerNames.SYSTEM_UI_DEFAULT, true); + } else { + centralSurfaces.onInputFocusTransfer( + mInputFocusTransferStarted, false /* cancel */, + 0 /* velocity */); + } } if (action == ACTION_UP || action == ACTION_CANCEL) { mInputFocusTransferStarted = false; - float velocity = (event.getY() - mInputFocusTransferStartY) - / (event.getEventTime() - mInputFocusTransferStartMillis); - centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted, - action == ACTION_CANCEL, - velocity); + + if (!mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) { + float velocity = (event.getY() - mInputFocusTransferStartY) + / (event.getEventTime() - mInputFocusTransferStartMillis); + centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted, + action == ACTION_CANCEL, + velocity); + } } event.recycle(); }); @@ -552,6 +571,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, + Provider<SceneInteractor> sceneInteractor, UserTracker userTracker, ScreenLifecycle screenLifecycle, WakefulnessLifecycle wakefulnessLifecycle, @@ -559,6 +579,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis DisplayTracker displayTracker, KeyguardUnlockAnimationController sysuiUnlockAnimationController, AssistUtils assistUtils, + FeatureFlags featureFlags, DumpManager dumpManager, Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder ) { @@ -568,6 +589,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } mContext = context; + mFeatureFlags = featureFlags; mMainExecutor = mainExecutor; mShellInterface = shellInterface; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; @@ -575,6 +597,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mHandler = new Handler(); mNavBarControllerLazy = navBarControllerLazy; mStatusBarWinController = statusBarWinController; + mSceneInteractor = sceneInteractor; mUserTracker = userTracker; mConnectionBackoffAttempts = 0; mRecentsComponentName = ComponentName.unflattenFromString(context.getString( diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index 4582370679ab..f03f040c206d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -18,11 +18,14 @@ package com.android.systemui.scene.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.data.repository.SceneContainerRepository +import com.android.systemui.scene.shared.model.RemoteUserInput import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.SceneTransitionModel import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow /** * Generic business logic and app state accessors for the scene framework. @@ -92,4 +95,14 @@ constructor( fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> { return repository.sceneTransitions(containerName) } + + private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null) + + /** A flow of motion events originating from outside of the scene framework. */ + val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow() + + /** Handles a remote user input. */ + fun onRemoteUserInput(input: RemoteUserInput) { + _remoteUserInput.value = input + } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt new file mode 100644 index 000000000000..680de590a3fc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/RemoteUserInput.kt @@ -0,0 +1,35 @@ +package com.android.systemui.scene.shared.model + +import android.view.MotionEvent + +/** A representation of user input that is used by the scene framework. */ +data class RemoteUserInput( + val x: Float, + val y: Float, + val action: RemoteUserInputAction, +) { + companion object { + fun translateMotionEvent(event: MotionEvent): RemoteUserInput { + return RemoteUserInput( + x = event.x, + y = event.y, + action = + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> RemoteUserInputAction.DOWN + MotionEvent.ACTION_MOVE -> RemoteUserInputAction.MOVE + MotionEvent.ACTION_UP -> RemoteUserInputAction.UP + MotionEvent.ACTION_CANCEL -> RemoteUserInputAction.CANCEL + else -> RemoteUserInputAction.UNKNOWN + } + ) + } + } +} + +enum class RemoteUserInputAction { + DOWN, + MOVE, + UP, + CANCEL, + UNKNOWN, +} diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt index c456be6e5ab2..b89179289a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt @@ -2,6 +2,7 @@ package com.android.systemui.scene.ui.view import android.content.Context import android.util.AttributeSet +import android.view.MotionEvent import android.view.View import com.android.systemui.scene.shared.model.Scene import com.android.systemui.scene.shared.model.SceneContainerConfig @@ -16,11 +17,15 @@ class SceneWindowRootView( context, attrs, ) { + + private lateinit var viewModel: SceneContainerViewModel + fun init( viewModel: SceneContainerViewModel, containerConfig: SceneContainerConfig, scenes: Set<Scene>, ) { + this.viewModel = viewModel SceneWindowRootViewBinder.bind( view = this@SceneWindowRootView, viewModel = viewModel, @@ -32,6 +37,14 @@ class SceneWindowRootView( ) } + override fun onTouchEvent(event: MotionEvent?): Boolean { + return event?.let { + viewModel.onRemoteUserInput(event) + true + } + ?: false + } + override fun setVisibility(visibility: Int) { // Do nothing. We don't want external callers to invoke this. Instead, we drive our own // visibility from our view-binder. diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt index 8c1ad9b4571b..005f48d9f250 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt @@ -16,7 +16,9 @@ package com.android.systemui.scene.ui.viewmodel +import android.view.MotionEvent import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.RemoteUserInput import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import kotlinx.coroutines.flow.StateFlow @@ -26,6 +28,9 @@ class SceneContainerViewModel( private val interactor: SceneInteractor, val containerName: String, ) { + /** A flow of motion events originating from outside of the scene framework. */ + val remoteUserInput: StateFlow<RemoteUserInput?> = interactor.remoteUserInput + /** * Keys of all scenes in the container. * @@ -49,4 +54,9 @@ class SceneContainerViewModel( fun setSceneTransitionProgress(progress: Float) { interactor.setSceneTransitionProgress(containerName, progress) } + + /** Handles a [MotionEvent] representing remote user input. */ + fun onRemoteUserInput(event: MotionEvent) { + interactor.onRemoteUserInput(RemoteUserInput.translateMotionEvent(event)) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 862f169b2176..4e136deab5e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -28,6 +28,9 @@ import com.android.systemui.Gefingerpoken import com.android.systemui.R import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.RemoteUserInput +import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController @@ -43,6 +46,7 @@ import com.android.systemui.util.view.ViewUtil import java.util.Optional import javax.inject.Inject import javax.inject.Named +import javax.inject.Provider private const val TAG = "PhoneStatusBarViewController" @@ -53,10 +57,12 @@ class PhoneStatusBarViewController private constructor( private val centralSurfaces: CentralSurfaces, private val shadeController: ShadeController, private val shadeViewController: ShadeViewController, + private val sceneInteractor: Provider<SceneInteractor>, private val shadeLogger: ShadeLogger, private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, private val userChipViewModel: StatusBarUserChipViewModel, private val viewUtil: ViewUtil, + private val featureFlags: FeatureFlags, private val configurationController: ConfigurationController ) : ViewController<PhoneStatusBarView>(view) { @@ -164,6 +170,16 @@ class PhoneStatusBarViewController private constructor( return false } + // If scene framework is enabled, route the touch to it and + // ignore the rest of the gesture. + if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) { + sceneInteractor.get() + .onRemoteUserInput(RemoteUserInput.translateMotionEvent(event)) + // TODO(b/291965119): remove once view is expanded to cover the status bar + sceneInteractor.get().setVisible(SceneContainerNames.SYSTEM_UI_DEFAULT, true) + return false + } + if (event.action == MotionEvent.ACTION_DOWN) { // If the view that would receive the touch is disabled, just have status // bar eat the gesture. @@ -225,6 +241,7 @@ class PhoneStatusBarViewController private constructor( private val centralSurfaces: CentralSurfaces, private val shadeController: ShadeController, private val shadeViewController: ShadeViewController, + private val sceneInteractor: Provider<SceneInteractor>, private val shadeLogger: ShadeLogger, private val viewUtil: ViewUtil, private val configurationController: ConfigurationController, @@ -245,10 +262,12 @@ class PhoneStatusBarViewController private constructor( centralSurfaces, shadeController, shadeViewController, + sceneInteractor, shadeLogger, statusBarMoveFromCenterAnimationController, userChipViewModel, viewUtil, + featureFlags, configurationController ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index 2a039dade059..68a6b3d62bae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -34,15 +34,21 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.ScreenDecorations; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; +import com.android.systemui.scene.domain.interactor.SceneInteractor; +import com.android.systemui.scene.shared.model.SceneContainerNames; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.util.kotlin.JavaAdapter; import java.io.PrintWriter; import javax.inject.Inject; +import javax.inject.Provider; /** * Manages what parts of the status bar are touchable. Clients are primarily UI that display in the @@ -78,6 +84,9 @@ public final class StatusBarTouchableRegionManager implements Dumpable { ConfigurationController configurationController, HeadsUpManagerPhone headsUpManager, ShadeExpansionStateManager shadeExpansionStateManager, + Provider<SceneInteractor> sceneInteractor, + Provider<JavaAdapter> javaAdapter, + FeatureFlags featureFlags, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController ) { mContext = context; @@ -115,6 +124,12 @@ public final class StatusBarTouchableRegionManager implements Dumpable { mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); + if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) { + javaAdapter.get().alwaysCollectFlow( + sceneInteractor.get().isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT), + this::onShadeExpansionFullyChanged); + } + mOnComputeInternalInsetsListener = this::onComputeInternalInsets; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt index 6bb13eacc135..49ece66e0cfd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt @@ -29,6 +29,7 @@ import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle @@ -49,11 +50,11 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.android.wm.shell.sysui.ShellInterface import com.google.common.util.concurrent.MoreExecutors -import dagger.Lazy import java.util.Optional import java.util.concurrent.Executor import org.junit.After @@ -82,6 +83,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { private val displayTracker = FakeDisplayTracker(mContext) private val fakeSystemClock = FakeSystemClock() private val sysUiState = SysUiState(displayTracker) + private val featureFlags = FakeFeatureFlags() private val screenLifecycle = ScreenLifecycle(dumpManager) private val wakefulnessLifecycle = WakefulnessLifecycle(mContext, null, fakeSystemClock, dumpManager) @@ -132,12 +134,13 @@ class OverviewProxyServiceTest : SysuiTestCase() { executor, commandQueue, shellInterface, - Lazy { navBarController }, - Lazy { Optional.of(centralSurfaces) }, - Lazy { shadeViewController }, + { navBarController }, + { Optional.of(centralSurfaces) }, + { shadeViewController }, navModeController, statusBarWinController, sysUiState, + mock(), userTracker, screenLifecycle, wakefulnessLifecycle, @@ -145,6 +148,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { displayTracker, sysuiUnlockAnimationController, assistUtils, + featureFlags, dumpManager, unfoldTransitionProgressForwarder ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index 3050c4edd24f..d2bbfa85604b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -100,4 +100,15 @@ class SceneInteractorTest : SysuiTestCase() { ) ) } + + @Test + fun remoteUserInput() = runTest { + val remoteUserInput by collectLastValue(underTest.remoteUserInput) + assertThat(remoteUserInput).isNull() + + for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) { + underTest.onRemoteUserInput(input) + assertThat(remoteUserInput).isEqualTo(input) + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt index 6882be7fe184..63ea918c904a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt @@ -18,14 +18,19 @@ package com.android.systemui.scene.ui.viewmodel +import android.view.MotionEvent import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.scene.SceneTestUtils +import com.android.systemui.scene.shared.model.RemoteUserInput +import com.android.systemui.scene.shared.model.RemoteUserInputAction import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.currentTime import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -68,4 +73,35 @@ class SceneContainerViewModelTest : SysuiTestCase() { underTest.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade)) } + + @Test + fun onRemoteUserInput() = runTest { + val remoteUserInput by collectLastValue(underTest.remoteUserInput) + assertThat(remoteUserInput).isNull() + + val inputs = + SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE.map { remoteUserInputToMotionEvent(it) } + + inputs.forEachIndexed { index, input -> + underTest.onRemoteUserInput(input) + assertThat(remoteUserInput).isEqualTo(SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE[index]) + } + } + + private fun TestScope.remoteUserInputToMotionEvent(input: RemoteUserInput): MotionEvent { + return MotionEvent.obtain( + currentTime, + currentTime, + when (input.action) { + RemoteUserInputAction.DOWN -> MotionEvent.ACTION_DOWN + RemoteUserInputAction.MOVE -> MotionEvent.ACTION_MOVE + RemoteUserInputAction.UP -> MotionEvent.ACTION_UP + RemoteUserInputAction.CANCEL -> MotionEvent.ACTION_CANCEL + RemoteUserInputAction.UNKNOWN -> MotionEvent.ACTION_OUTSIDE + }, + input.x, + input.y, + 0 + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 28193db01013..7de0075c45ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.shade.ShadeControllerImpl import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController @@ -50,6 +51,7 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import java.util.Optional +import javax.inject.Provider @SmallTest class PhoneStatusBarViewControllerTest : SysuiTestCase() { @@ -73,6 +75,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { @Mock private lateinit var shadeControllerImpl: ShadeControllerImpl @Mock + private lateinit var sceneInteractor: Provider<SceneInteractor> + @Mock private lateinit var shadeLogger: ShadeLogger @Mock private lateinit var viewUtil: ViewUtil @@ -197,6 +201,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { centralSurfacesImpl, shadeControllerImpl, shadeViewController, + sceneInteractor, shadeLogger, viewUtil, configurationController diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt index 931798130499..f39982f54441 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt @@ -38,6 +38,8 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.scene.data.repository.SceneContainerRepository import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.RemoteUserInput +import com.android.systemui.scene.shared.model.RemoteUserInputAction import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey @@ -217,5 +219,14 @@ class SceneTestUtils( companion object { const val CONTAINER_1 = SceneContainerNames.SYSTEM_UI_DEFAULT const val CONTAINER_2 = "container2" + + val REMOTE_INPUT_DOWN_GESTURE = + listOf( + RemoteUserInput(10f, 10f, RemoteUserInputAction.DOWN), + RemoteUserInput(10f, 20f, RemoteUserInputAction.MOVE), + RemoteUserInput(10f, 30f, RemoteUserInputAction.MOVE), + RemoteUserInput(10f, 40f, RemoteUserInputAction.MOVE), + RemoteUserInput(10f, 40f, RemoteUserInputAction.UP), + ) } } |