Make flexiglass window visible when swiping on launcher and status bar
When a touch is going to be proxied from launcher to shade, the flexiglass window is made visible so touches can slip onto it. Touches on the status bar are piped into flexiglass through SceneInteractor. Both invocation methods open the shade scene directly at the moment, awaiting various blockers. Bug: 290682366 Test: new unit test Test: manually verified MotionEvents being detected in flexiglass from swipes on launcher and status bar Test: manually verified no behavior is changed when the feature flag is disabled Change-Id: I0feb4b5b38f3bf00ac846e9bba735dbeff145f3c
This commit is contained in:
@@ -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),
|
||||
) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user