Loading packages/SystemUI/src/com/android/systemui/log/dagger/CommunalTouchLog.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.log.dagger import javax.inject.Qualifier /** A [com.android.systemui.log.LogBuffer] for communal touch-handling logging. */ @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class CommunalTouchLog packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +10 −0 Original line number Diff line number Diff line Loading @@ -617,6 +617,16 @@ public class LogModule { return factory.create("CommunalLog", 250); } /** * Provides a {@link LogBuffer} for communal touch-handling logs. */ @Provides @SysUISingleton @CommunalTouchLog public static LogBuffer provideCommunalTouchLogBuffer(LogBufferFactory factory) { return factory.create("CommunalTouchLog", 250); } /** * Provides a {@link TableLogBuffer} for communal-related logs. */ Loading packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +112 −25 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.lifecycleScope Loading @@ -55,6 +57,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalTouchLog import com.android.systemui.media.controls.ui.controller.KeyguardMediaController import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag Loading Loading @@ -91,8 +96,10 @@ constructor( @Communal private val dataSourceDelegator: SceneDataSourceDelegator, private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController, private val keyguardMediaController: KeyguardMediaController, private val lockscreenSmartspaceController: LockscreenSmartspaceController private val lockscreenSmartspaceController: LockscreenSmartspaceController, @CommunalTouchLog logBuffer: LogBuffer, ) : LifecycleOwner { private val logger = Logger(logBuffer, "GlanceableHubContainerController") private class CommunalWrapper(context: Context) : FrameLayout(context) { private val consumers: MutableSet<Consumer<Boolean>> = ArraySet() Loading Loading @@ -142,6 +149,17 @@ constructor( */ private var isTrackingHubTouch = false /** * True if a touch gesture on the lock screen has been consumed by the shade/bouncer and thus * should be ignored by the hub. * * This is necessary on the lock screen as gestures on an empty spot go through special touch * handling logic in [NotificationShadeWindowViewController] that decides if they should go to * the shade or bouncer. Once the shade or bouncer are moving, we don't get the typical cancel * event so to play nice, we ignore touches once we see the shade or bouncer are opening. */ private var touchTakenByKeyguardGesture = false /** * True if the hub UI is fully open, meaning it should receive touch input. * Loading Loading @@ -206,6 +224,21 @@ constructor( */ private var isDreaming = false /** Observes and logs state when the lifecycle that controls the [touchMonitor] updates. */ private val touchLifecycleLogger: LifecycleObserver = LifecycleEventObserver { _, event -> logger.d({ "Touch handler lifecycle changed to $str1. hubShowing: $bool1, " + "shadeShowingAndConsumingTouches: $bool2, " + "anyBouncerShowing: $bool3, inEditModeTransition: $bool4" }) { str1 = event.toString() bool1 = hubShowing bool2 = shadeShowingAndConsumingTouches bool3 = anyBouncerShowing bool4 = inEditModeTransition } } /** Returns a flow that tracks whether communal hub is available. */ fun communalAvailable(): Flow<Boolean> = anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen) Loading Loading @@ -268,6 +301,7 @@ constructor( init() } } lifecycleRegistry.addObserver(touchLifecycleLogger) lifecycleRegistry.currentState = Lifecycle.State.CREATED communalContainerView = containerView Loading Loading @@ -328,6 +362,9 @@ constructor( backGestureInset ) } logger.d({ "Insets updated: $str1" }) { str1 = containerView.systemGestureExclusionRects.toString() } } } Loading @@ -343,6 +380,9 @@ constructor( ), { anyBouncerShowing = it if (hubShowing) { logger.d({ "New value for anyBouncerShowing: $bool1" }) { bool1 = it } } updateTouchHandlingState() } ) Loading Loading @@ -396,7 +436,13 @@ constructor( // If the shade reaches full expansion without interaction, then we should allow it // to consume touches rather than handling it here until it disappears. shadeShowingAndConsumingTouches = userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive (userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive).also { if (it != shadeShowingAndConsumingTouches && hubShowing) { logger.d({ "New value for shadeShowingAndConsumingTouches: $bool1" }) { bool1 = it } } } updateTouchHandlingState() } ) Loading @@ -404,6 +450,7 @@ constructor( communalContainerWrapper = CommunalWrapper(containerView.context) communalContainerWrapper?.addView(communalContainerView) logger.d("Hub container initialized") return communalContainerWrapper!! } Loading Loading @@ -446,6 +493,10 @@ constructor( (it.parent as ViewGroup).removeView(it) communalContainerWrapper = null } lifecycleRegistry.removeObserver(touchLifecycleLogger) logger.d("Hub container disposed") } /** Loading @@ -463,15 +514,20 @@ constructor( // In the case that we are handling full swipes on the lockscreen, are on the lockscreen, // and the touch is within the horizontal notification band on the screen, do not process // the touch. if ( !hubShowing && (!notificationStackScrollLayoutController.isBelowLastNotification(ev.x, ev.y) || keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt()) || lockscreenSmartspaceController.isWithinSmartspaceBounds( ev.x.toInt(), ev.y.toInt() )) ) { val touchOnNotifications = !notificationStackScrollLayoutController.isBelowLastNotification(ev.x, ev.y) val touchOnUmo = keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt()) val touchOnSmartspace = lockscreenSmartspaceController.isWithinSmartspaceBounds(ev.x.toInt(), ev.y.toInt()) if (!hubShowing && (touchOnNotifications || touchOnUmo || touchOnSmartspace)) { logger.d({ "Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " + "touchOnSmartspace: $bool3" }) { bool1 = touchOnNotifications bool2 = touchOnUmo bool3 = touchOnSmartspace } return false } Loading @@ -487,12 +543,56 @@ constructor( val hubOccluded = anyBouncerShowing || shadeShowingAndConsumingTouches if ((isDown || isMove) && !hubOccluded) { if (isDown) { logger.d({ "Touch started. x: $int1, y: $int2, hubShowing: $bool1, isDreaming: $bool2, " + "onLockscreen: $bool3" }) { int1 = ev.x.toInt() int2 = ev.y.toInt() bool1 = hubShowing bool2 = isDreaming bool3 = onLockscreen } } isTrackingHubTouch = true } if (isTrackingHubTouch) { // On the lock screen, our touch handlers are not active and we rely on the NSWVC's // touch handling for gestures on blank areas, which can go up to show the bouncer or // down to show the notification shade. We see the touches first and they are not // consumed and cancelled like on the dream or hub so we have to gracefully ignore them // if the shade or bouncer are handling them. This issue only applies to touches on the // keyguard itself, once the bouncer or shade are fully open, our logic stops us from // taking touches. touchTakenByKeyguardGesture = (onLockscreen && (shadeConsumingTouches || anyBouncerShowing)).also { if (it != touchTakenByKeyguardGesture && it) { logger.d( "Lock screen touch consumed by shade or bouncer, ignoring " + "subsequent touches" ) } } if (isUp || isCancel) { logger.d({ val endReason = if (bool1) "up" else "cancel" "Touch ended with $endReason. x: $int1, y: $int2, " + "shadeConsumingTouches: $bool2, anyBouncerShowing: $bool3" }) { int1 = ev.x.toInt() int2 = ev.y.toInt() bool1 = isUp bool2 = shadeConsumingTouches bool3 = anyBouncerShowing } isTrackingHubTouch = false // Clear out touch taken state to ensure the up/cancel event still gets dispatched // to the hub. This is necessary as the hub always receives at least the initial // down even if the shade or bouncer end up handling the touch. touchTakenByKeyguardGesture = false } return dispatchTouchEvent(ev) } Loading @@ -513,21 +613,8 @@ constructor( return true } try { // On the lock screen, our touch handlers are not active and we rely on the NSWVC's // touch handling for gestures on blank areas, which can go up to show the bouncer or // down to show the notification shade. We see the touches first and they are not // consumed and cancelled like on the dream or hub so we have to gracefully ignore them // if the shade or bouncer are handling them. This issue only applies to touches on the // keyguard itself, once the bouncer or shade are fully open, our logic stops us from // taking touches. val touchTaken = onLockscreen && (shadeConsumingTouches || anyBouncerShowing) // Only dispatch touches to communal if not already handled or the touch is ending, // meaning the event is an up or cancel. This is necessary as the hub always receives at // least the initial down even if the shade or bouncer end up handling the touch. val dispatchToCommunal = !touchTaken || !isTrackingHubTouch var handled = false if (dispatchToCommunal) { if (!touchTakenByKeyguardGesture) { communalContainerWrapper?.dispatchTouchEvent(ev) { if (it) { handled = true Loading packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +9 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.controller.keyguardMediaController import com.android.systemui.res.R import com.android.systemui.scene.shared.model.sceneDataSourceDelegator Loading Loading @@ -140,7 +141,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) } testableLooper = TestableLooper.get(this) Loading Loading @@ -186,7 +188,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) // First call succeeds. Loading Loading @@ -214,7 +217,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED) Loading @@ -237,7 +241,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) // Only initView without attaching a view as we don't want the flows to start collecting Loading Loading
packages/SystemUI/src/com/android/systemui/log/dagger/CommunalTouchLog.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.log.dagger import javax.inject.Qualifier /** A [com.android.systemui.log.LogBuffer] for communal touch-handling logging. */ @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class CommunalTouchLog
packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +10 −0 Original line number Diff line number Diff line Loading @@ -617,6 +617,16 @@ public class LogModule { return factory.create("CommunalLog", 250); } /** * Provides a {@link LogBuffer} for communal touch-handling logs. */ @Provides @SysUISingleton @CommunalTouchLog public static LogBuffer provideCommunalTouchLogBuffer(LogBufferFactory factory) { return factory.create("CommunalTouchLog", 250); } /** * Provides a {@link TableLogBuffer} for communal-related logs. */ Loading
packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +112 −25 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.lifecycleScope Loading @@ -55,6 +57,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalTouchLog import com.android.systemui.media.controls.ui.controller.KeyguardMediaController import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag Loading Loading @@ -91,8 +96,10 @@ constructor( @Communal private val dataSourceDelegator: SceneDataSourceDelegator, private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController, private val keyguardMediaController: KeyguardMediaController, private val lockscreenSmartspaceController: LockscreenSmartspaceController private val lockscreenSmartspaceController: LockscreenSmartspaceController, @CommunalTouchLog logBuffer: LogBuffer, ) : LifecycleOwner { private val logger = Logger(logBuffer, "GlanceableHubContainerController") private class CommunalWrapper(context: Context) : FrameLayout(context) { private val consumers: MutableSet<Consumer<Boolean>> = ArraySet() Loading Loading @@ -142,6 +149,17 @@ constructor( */ private var isTrackingHubTouch = false /** * True if a touch gesture on the lock screen has been consumed by the shade/bouncer and thus * should be ignored by the hub. * * This is necessary on the lock screen as gestures on an empty spot go through special touch * handling logic in [NotificationShadeWindowViewController] that decides if they should go to * the shade or bouncer. Once the shade or bouncer are moving, we don't get the typical cancel * event so to play nice, we ignore touches once we see the shade or bouncer are opening. */ private var touchTakenByKeyguardGesture = false /** * True if the hub UI is fully open, meaning it should receive touch input. * Loading Loading @@ -206,6 +224,21 @@ constructor( */ private var isDreaming = false /** Observes and logs state when the lifecycle that controls the [touchMonitor] updates. */ private val touchLifecycleLogger: LifecycleObserver = LifecycleEventObserver { _, event -> logger.d({ "Touch handler lifecycle changed to $str1. hubShowing: $bool1, " + "shadeShowingAndConsumingTouches: $bool2, " + "anyBouncerShowing: $bool3, inEditModeTransition: $bool4" }) { str1 = event.toString() bool1 = hubShowing bool2 = shadeShowingAndConsumingTouches bool3 = anyBouncerShowing bool4 = inEditModeTransition } } /** Returns a flow that tracks whether communal hub is available. */ fun communalAvailable(): Flow<Boolean> = anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen) Loading Loading @@ -268,6 +301,7 @@ constructor( init() } } lifecycleRegistry.addObserver(touchLifecycleLogger) lifecycleRegistry.currentState = Lifecycle.State.CREATED communalContainerView = containerView Loading Loading @@ -328,6 +362,9 @@ constructor( backGestureInset ) } logger.d({ "Insets updated: $str1" }) { str1 = containerView.systemGestureExclusionRects.toString() } } } Loading @@ -343,6 +380,9 @@ constructor( ), { anyBouncerShowing = it if (hubShowing) { logger.d({ "New value for anyBouncerShowing: $bool1" }) { bool1 = it } } updateTouchHandlingState() } ) Loading Loading @@ -396,7 +436,13 @@ constructor( // If the shade reaches full expansion without interaction, then we should allow it // to consume touches rather than handling it here until it disappears. shadeShowingAndConsumingTouches = userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive (userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive).also { if (it != shadeShowingAndConsumingTouches && hubShowing) { logger.d({ "New value for shadeShowingAndConsumingTouches: $bool1" }) { bool1 = it } } } updateTouchHandlingState() } ) Loading @@ -404,6 +450,7 @@ constructor( communalContainerWrapper = CommunalWrapper(containerView.context) communalContainerWrapper?.addView(communalContainerView) logger.d("Hub container initialized") return communalContainerWrapper!! } Loading Loading @@ -446,6 +493,10 @@ constructor( (it.parent as ViewGroup).removeView(it) communalContainerWrapper = null } lifecycleRegistry.removeObserver(touchLifecycleLogger) logger.d("Hub container disposed") } /** Loading @@ -463,15 +514,20 @@ constructor( // In the case that we are handling full swipes on the lockscreen, are on the lockscreen, // and the touch is within the horizontal notification band on the screen, do not process // the touch. if ( !hubShowing && (!notificationStackScrollLayoutController.isBelowLastNotification(ev.x, ev.y) || keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt()) || lockscreenSmartspaceController.isWithinSmartspaceBounds( ev.x.toInt(), ev.y.toInt() )) ) { val touchOnNotifications = !notificationStackScrollLayoutController.isBelowLastNotification(ev.x, ev.y) val touchOnUmo = keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt()) val touchOnSmartspace = lockscreenSmartspaceController.isWithinSmartspaceBounds(ev.x.toInt(), ev.y.toInt()) if (!hubShowing && (touchOnNotifications || touchOnUmo || touchOnSmartspace)) { logger.d({ "Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " + "touchOnSmartspace: $bool3" }) { bool1 = touchOnNotifications bool2 = touchOnUmo bool3 = touchOnSmartspace } return false } Loading @@ -487,12 +543,56 @@ constructor( val hubOccluded = anyBouncerShowing || shadeShowingAndConsumingTouches if ((isDown || isMove) && !hubOccluded) { if (isDown) { logger.d({ "Touch started. x: $int1, y: $int2, hubShowing: $bool1, isDreaming: $bool2, " + "onLockscreen: $bool3" }) { int1 = ev.x.toInt() int2 = ev.y.toInt() bool1 = hubShowing bool2 = isDreaming bool3 = onLockscreen } } isTrackingHubTouch = true } if (isTrackingHubTouch) { // On the lock screen, our touch handlers are not active and we rely on the NSWVC's // touch handling for gestures on blank areas, which can go up to show the bouncer or // down to show the notification shade. We see the touches first and they are not // consumed and cancelled like on the dream or hub so we have to gracefully ignore them // if the shade or bouncer are handling them. This issue only applies to touches on the // keyguard itself, once the bouncer or shade are fully open, our logic stops us from // taking touches. touchTakenByKeyguardGesture = (onLockscreen && (shadeConsumingTouches || anyBouncerShowing)).also { if (it != touchTakenByKeyguardGesture && it) { logger.d( "Lock screen touch consumed by shade or bouncer, ignoring " + "subsequent touches" ) } } if (isUp || isCancel) { logger.d({ val endReason = if (bool1) "up" else "cancel" "Touch ended with $endReason. x: $int1, y: $int2, " + "shadeConsumingTouches: $bool2, anyBouncerShowing: $bool3" }) { int1 = ev.x.toInt() int2 = ev.y.toInt() bool1 = isUp bool2 = shadeConsumingTouches bool3 = anyBouncerShowing } isTrackingHubTouch = false // Clear out touch taken state to ensure the up/cancel event still gets dispatched // to the hub. This is necessary as the hub always receives at least the initial // down even if the shade or bouncer end up handling the touch. touchTakenByKeyguardGesture = false } return dispatchTouchEvent(ev) } Loading @@ -513,21 +613,8 @@ constructor( return true } try { // On the lock screen, our touch handlers are not active and we rely on the NSWVC's // touch handling for gestures on blank areas, which can go up to show the bouncer or // down to show the notification shade. We see the touches first and they are not // consumed and cancelled like on the dream or hub so we have to gracefully ignore them // if the shade or bouncer are handling them. This issue only applies to touches on the // keyguard itself, once the bouncer or shade are fully open, our logic stops us from // taking touches. val touchTaken = onLockscreen && (shadeConsumingTouches || anyBouncerShowing) // Only dispatch touches to communal if not already handled or the touch is ending, // meaning the event is an up or cancel. This is necessary as the hub always receives at // least the initial down even if the shade or bouncer end up handling the touch. val dispatchToCommunal = !touchTaken || !isTrackingHubTouch var handled = false if (dispatchToCommunal) { if (!touchTakenByKeyguardGesture) { communalContainerWrapper?.dispatchTouchEvent(ev) { if (it) { handled = true Loading
packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +9 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.controller.keyguardMediaController import com.android.systemui.res.R import com.android.systemui.scene.shared.model.sceneDataSourceDelegator Loading Loading @@ -140,7 +141,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) } testableLooper = TestableLooper.get(this) Loading Loading @@ -186,7 +188,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) // First call succeeds. Loading Loading @@ -214,7 +217,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED) Loading @@ -237,7 +241,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { kosmos.sceneDataSourceDelegator, kosmos.notificationStackScrollLayoutController, kosmos.keyguardMediaController, kosmos.lockscreenSmartspaceController kosmos.lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest") ) // Only initView without attaching a view as we don't want the flows to start collecting Loading