Loading packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt +0 −52 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -121,45 +110,4 @@ class SysUiViewModelTest : SysuiTestCase() { 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 } } } packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt +3 −38 Original line number Diff line number Diff line Loading @@ -226,26 +226,6 @@ private fun inferTraceSectionName(): String { } } /** * 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 Loading @@ -253,7 +233,7 @@ suspend fun View.repeatOnWindowLifecycle( * * 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 { Loading @@ -269,7 +249,7 @@ suspend fun View.repeatWhenAttachedToWindow(block: suspend CoroutineScope.() -> * * 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 { Loading @@ -285,7 +265,7 @@ suspend fun View.repeatWhenWindowIsVisible(block: suspend CoroutineScope.() -> U * * 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 { Loading @@ -294,21 +274,6 @@ suspend fun View.repeatWhenWindowHasFocus(block: suspend CoroutineScope.() -> Un 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 = Loading packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt +7 −20 Original line number Diff line number Diff line Loading @@ -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() { Loading @@ -38,20 +37,8 @@ abstract class SysUiViewModel : SafeActivatable() { 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 } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt +29 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -33,6 +33,7 @@ import com.android.systemui.util.kotlin.launchAndDispose 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 Loading @@ -45,7 +46,7 @@ constructor( 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) { Loading @@ -60,14 +61,12 @@ constructor( } 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 -> suspend fun bind() = coroutineScope { launchAndDispose { updateViewPosition() view.asView().onLayoutChanged { updateViewPosition() } Loading @@ -81,9 +80,7 @@ constructor( 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.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } } launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } } launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +5 −13 Original line number Diff line number Diff line Loading @@ -19,9 +19,9 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel 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 Loading @@ -33,11 +33,9 @@ import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrim 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 Loading @@ -45,8 +43,9 @@ import kotlinx.coroutines.flow.flowOf 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, Loading @@ -55,9 +54,7 @@ constructor( // 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 Loading Loading @@ -189,9 +186,4 @@ constructor( keyguardInteractor.get().isDozing.dumpWhileCollecting("isDozing") } } @AssistedFactory interface Factory { fun create(): NotificationScrollViewModel } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt +0 −52 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -121,45 +110,4 @@ class SysUiViewModelTest : SysuiTestCase() { 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 } } }
packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt +3 −38 Original line number Diff line number Diff line Loading @@ -226,26 +226,6 @@ private fun inferTraceSectionName(): String { } } /** * 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 Loading @@ -253,7 +233,7 @@ suspend fun View.repeatOnWindowLifecycle( * * 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 { Loading @@ -269,7 +249,7 @@ suspend fun View.repeatWhenAttachedToWindow(block: suspend CoroutineScope.() -> * * 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 { Loading @@ -285,7 +265,7 @@ suspend fun View.repeatWhenWindowIsVisible(block: suspend CoroutineScope.() -> U * * 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 { Loading @@ -294,21 +274,6 @@ suspend fun View.repeatWhenWindowHasFocus(block: suspend CoroutineScope.() -> Un 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 = Loading
packages/SystemUI/src/com/android/systemui/lifecycle/SysUiViewModel.kt +7 −20 Original line number Diff line number Diff line Loading @@ -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() { Loading @@ -38,20 +37,8 @@ abstract class SysUiViewModel : SafeActivatable() { 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 }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt +29 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -33,6 +33,7 @@ import com.android.systemui.util.kotlin.launchAndDispose 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 Loading @@ -45,7 +46,7 @@ constructor( 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) { Loading @@ -60,14 +61,12 @@ constructor( } 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 -> suspend fun bind() = coroutineScope { launchAndDispose { updateViewPosition() view.asView().onLayoutChanged { updateViewPosition() } Loading @@ -81,9 +80,7 @@ constructor( 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.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } } launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } } launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +5 −13 Original line number Diff line number Diff line Loading @@ -19,9 +19,9 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel 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 Loading @@ -33,11 +33,9 @@ import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrim 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 Loading @@ -45,8 +43,9 @@ import kotlinx.coroutines.flow.flowOf 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, Loading @@ -55,9 +54,7 @@ constructor( // 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 Loading Loading @@ -189,9 +186,4 @@ constructor( keyguardInteractor.get().isDozing.dumpWhileCollecting("isDozing") } } @AssistedFactory interface Factory { fun create(): NotificationScrollViewModel } }