Revert "Add View.viewModel utility"
This reverts commit 08cedcebf76dec5149b944b92d731107a4c24e5b.
Reason for revert: Droidmonitor created revert due to b/357987442. Will be verifying through ABTD before submission.
Change-Id: I3425e680d6ccbd42b71d2306ff503d8c7c9ee1bb
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
index 46b370f..d1f908d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
@@ -16,27 +16,16 @@
package com.android.systemui.lifecycle
-import android.view.View
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.Assert
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.awaitCancellation
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.argumentCaptor
-import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.stub
-import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -121,45 +110,4 @@
assertThat(isActive).isFalse()
}
-
- @Test
- fun viewModel_viewBinder() = runTest {
- Assert.setTestThread(Thread.currentThread())
-
- val view: View = mock { on { isAttachedToWindow } doReturn false }
- val viewModel = FakeViewModel()
- backgroundScope.launch {
- view.viewModel(
- minWindowLifecycleState = WindowLifecycleState.ATTACHED,
- factory = { viewModel },
- ) {
- awaitCancellation()
- }
- }
- runCurrent()
-
- assertThat(viewModel.isActivated).isFalse()
-
- view.stub { on { isAttachedToWindow } doReturn true }
- argumentCaptor<View.OnAttachStateChangeListener>()
- .apply { verify(view).addOnAttachStateChangeListener(capture()) }
- .allValues
- .forEach { it.onViewAttachedToWindow(view) }
- runCurrent()
-
- assertThat(viewModel.isActivated).isTrue()
- }
-}
-
-private class FakeViewModel : SysUiViewModel() {
- var isActivated = false
-
- override suspend fun onActivated() {
- isActivated = true
- try {
- awaitCancellation()
- } finally {
- isActivated = false
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index c2b5d98..661da6d 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -227,33 +227,13 @@
}
/**
- * Runs the given [block] in a new coroutine when `this` [View]'s Window's [WindowLifecycleState] is
- * at least at [state] (or immediately after calling this function if the window is already at least
- * at [state]), automatically canceling the work when the window is no longer at least at that
- * state.
- *
- * [block] may be run multiple times, running once per every time this` [View]'s Window's
- * [WindowLifecycleState] becomes at least at [state].
- */
-suspend fun View.repeatOnWindowLifecycle(
- state: WindowLifecycleState,
- block: suspend CoroutineScope.() -> Unit,
-): Nothing {
- when (state) {
- WindowLifecycleState.ATTACHED -> repeatWhenAttachedToWindow(block)
- WindowLifecycleState.VISIBLE -> repeatWhenWindowIsVisible(block)
- WindowLifecycleState.FOCUSED -> repeatWhenWindowHasFocus(block)
- }
-}
-
-/**
* Runs the given [block] every time the [View] becomes attached (or immediately after calling this
* function, if the view was already attached), automatically canceling the work when the view
* becomes detached.
*
* Only use from the main thread.
*
- * [block] may be run multiple times, running once per every time the view is attached.
+ * The [block] may be run multiple times, running once per every time the view is attached.
*/
@MainThread
suspend fun View.repeatWhenAttachedToWindow(block: suspend CoroutineScope.() -> Unit): Nothing {
@@ -269,7 +249,7 @@
*
* Only use from the main thread.
*
- * [block] may be run multiple times, running once per every time the window becomes visible.
+ * The [block] may be run multiple times, running once per every time the window becomes visible.
*/
@MainThread
suspend fun View.repeatWhenWindowIsVisible(block: suspend CoroutineScope.() -> Unit): Nothing {
@@ -285,7 +265,7 @@
*
* Only use from the main thread.
*
- * [block] may be run multiple times, running once per every time the window is focused.
+ * The [block] may be run multiple times, running once per every time the window is focused.
*/
@MainThread
suspend fun View.repeatWhenWindowHasFocus(block: suspend CoroutineScope.() -> Unit): Nothing {
@@ -294,21 +274,6 @@
awaitCancellation() // satisfies return type of Nothing
}
-/** Lifecycle states for a [View]'s interaction with a [android.view.Window]. */
-enum class WindowLifecycleState {
- /** Indicates that the [View] is attached to a [android.view.Window]. */
- ATTACHED,
- /**
- * Indicates that the [View] is attached to a [android.view.Window], and the window is visible.
- */
- VISIBLE,
- /**
- * Indicates that the [View] is attached to a [android.view.Window], and the window is visible
- * and focused.
- */
- FOCUSED
-}
-
private val View.isAttached
get() = conflatedCallbackFlow {
val onAttachListener =
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
index 7731481..0af5fea 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt
@@ -16,10 +16,9 @@
package com.android.systemui.lifecycle
-import android.view.View
import androidx.compose.runtime.Composable
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
/** Base class for all System UI view-models. */
abstract class SysUiViewModel : SafeActivatable() {
@@ -38,20 +37,8 @@
fun <T : SysUiViewModel> rememberViewModel(
key: Any = Unit,
factory: () -> T,
-): T = rememberActivated(key, factory)
-
-/**
- * Invokes [block] in a new coroutine with a new [SysUiViewModel] that is automatically activated
- * whenever `this` [View]'s Window's [WindowLifecycleState] is at least at
- * [minWindowLifecycleState], and is automatically canceled once that is no longer the case.
- */
-suspend fun <T : SysUiViewModel> View.viewModel(
- minWindowLifecycleState: WindowLifecycleState,
- factory: () -> T,
- block: suspend CoroutineScope.(T) -> Unit,
-): Nothing =
- repeatOnWindowLifecycle(minWindowLifecycleState) {
- val instance = factory()
- launch { instance.activate() }
- block(instance)
- }
+): T {
+ val instance = remember(key) { factory() }
+ LaunchedEffect(instance) { instance.activate() }
+ return instance
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index a30b877..fd08e89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -17,14 +17,14 @@
package com.android.systemui.statusbar.notification.stack.ui.viewbinder
import android.util.Log
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.view.onLayoutChanged
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationScrollViewModel
@@ -33,6 +33,7 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
@@ -45,7 +46,7 @@
dumpManager: DumpManager,
@Main private val mainImmediateDispatcher: CoroutineDispatcher,
private val view: NotificationScrollView,
- private val viewModelFactory: NotificationScrollViewModel.Factory,
+ private val viewModel: NotificationScrollViewModel,
private val configuration: ConfigurationState,
) : FlowDumperImpl(dumpManager) {
@@ -60,42 +61,38 @@
}
fun bindWhileAttached(): DisposableHandle {
- return view.asView().repeatWhenAttached(mainImmediateDispatcher) { bind() }
+ return view.asView().repeatWhenAttached(mainImmediateDispatcher) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) { bind() }
+ }
}
- suspend fun bind(): Nothing =
- view.asView().viewModel(
- minWindowLifecycleState = WindowLifecycleState.ATTACHED,
- factory = viewModelFactory::create,
- ) { viewModel ->
- launchAndDispose {
- updateViewPosition()
- view.asView().onLayoutChanged { updateViewPosition() }
- }
+ suspend fun bind() = coroutineScope {
+ launchAndDispose {
+ updateViewPosition()
+ view.asView().onLayoutChanged { updateViewPosition() }
+ }
- launch {
- viewModel
- .shadeScrimShape(cornerRadius = scrimRadius, viewLeftOffset = viewLeftOffset)
- .collect { view.setScrimClippingShape(it) }
- }
+ launch {
+ viewModel
+ .shadeScrimShape(cornerRadius = scrimRadius, viewLeftOffset = viewLeftOffset)
+ .collect { view.setScrimClippingShape(it) }
+ }
- launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
- launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
- launch {
- viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) }
- }
- launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } }
- launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } }
+ launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
+ launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
+ launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } }
+ launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } }
+ launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } }
- launchAndDispose {
- view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
- view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer)
- DisposableHandle {
- view.setSyntheticScrollConsumer(null)
- view.setCurrentGestureOverscrollConsumer(null)
- }
+ launchAndDispose {
+ view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
+ view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer)
+ DisposableHandle {
+ view.setSyntheticScrollConsumer(null)
+ view.setCurrentGestureOverscrollConsumer(null)
}
}
+ }
/** flow of the scrim clipping radius */
private val scrimRadius: Flow<Int>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 4281025..2ba79a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -19,9 +19,9 @@
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.lifecycle.SysUiViewModel
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.SceneFamilies
@@ -33,11 +33,9 @@
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_DELAYED_STACK_FADE_IN
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA
-import com.android.systemui.util.kotlin.FlowDumper
import com.android.systemui.util.kotlin.FlowDumperImpl
import dagger.Lazy
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -45,8 +43,9 @@
import kotlinx.coroutines.flow.map
/** ViewModel which represents the state of the NSSL/Controller in the world of flexiglass */
+@SysUISingleton
class NotificationScrollViewModel
-@AssistedInject
+@Inject
constructor(
dumpManager: DumpManager,
stackAppearanceInteractor: NotificationStackAppearanceInteractor,
@@ -55,9 +54,7 @@
// TODO(b/336364825) Remove Lazy when SceneContainerFlag is released -
// while the flag is off, creating this object too early results in a crash
keyguardInteractor: Lazy<KeyguardInteractor>,
-) : FlowDumper by FlowDumperImpl(dumpManager, "NotificationScrollViewModel"),
- SysUiViewModel() {
-
+) : FlowDumperImpl(dumpManager) {
/**
* The expansion fraction of the notification stack. It should go from 0 to 1 when transitioning
* from Gone to Shade scenes, and remain at 1 when in Lockscreen or Shade scenes and while
@@ -189,9 +186,4 @@
keyguardInteractor.get().isDozing.dumpWhileCollecting("isDozing")
}
}
-
- @AssistedFactory
- interface Factory {
- fun create(): NotificationScrollViewModel
- }
}