Merge "Make flexiglass window visible when swiping on launcher and status bar" into udc-qpr-dev

This commit is contained in:
Shawn Lee
2023-07-24 15:57:03 +00:00
committed by Android (Google) Code Review
13 changed files with 215 additions and 20 deletions

View File

@@ -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),
) {

View File

@@ -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(

View File

@@ -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
}
}

View File

@@ -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,
}

View File

@@ -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.

View File

@@ -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))
}
}

View File

@@ -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
)
}

View File

@@ -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;
}

View File

@@ -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
)

View File

@@ -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)
}
}
}

View File

@@ -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
)
}
}

View File

@@ -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

View File

@@ -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),
)
}
}