diff options
11 files changed, 237 insertions, 60 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt index fd9f5f02ee62..20dfd3e11947 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.shade.display import android.view.Display import android.view.Display.TYPE_EXTERNAL +import android.view.MotionEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -28,11 +29,16 @@ import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.shade.domain.interactor.notificationElement +import com.android.systemui.shade.domain.interactor.qsElement +import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test import kotlinx.coroutines.test.runTest import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock @SmallTest @RunWith(AndroidJUnit4::class) @@ -50,9 +56,19 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { keyguardRepository, testScope.backgroundScope, shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked, + shadeInteractor = { kosmos.shadeInteractor }, + { kosmos.qsElement }, + { kosmos.notificationElement }, ) } + private fun createMotionEventForDisplay(displayId: Int, xCoordinate: Float = 0f): MotionEvent { + return mock<MotionEvent> { + on { getX() } doReturn xCoordinate + on { getDisplayId() } doReturn displayId + } + } + @Test fun displayId_defaultToDefaultDisplay() { val underTest = createUnderTest() @@ -67,7 +83,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(2) + underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) } @@ -79,7 +95,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { val displayIds by collectValues(underTest.displayId) assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) - underTest.onStatusBarTouched(2) + underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) // Never set, as 2 was not a display according to the repository. assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) @@ -92,7 +108,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(2) + underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) @@ -108,7 +124,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(2) + underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) @@ -124,7 +140,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(2) + underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) @@ -136,4 +152,48 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { assertThat(displayId).isEqualTo(2) } + + @Test + fun onStatusBarTouched_leftSide_intentSetToNotifications() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + + underTest.onStatusBarTouched( + createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), + STATUS_BAR_WIDTH, + ) + + assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement) + } + + @Test + fun onStatusBarTouched_rightSide_intentSetToQs() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + + underTest.onStatusBarTouched( + createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.95f), + STATUS_BAR_WIDTH, + ) + + assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.qsElement) + } + + @Test + fun onStatusBarTouched_nullAfterConsumed() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + + underTest.onStatusBarTouched( + createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), + STATUS_BAR_WIDTH, + ) + assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement) + + assertThat(underTest.consumeExpansionIntent()).isNull() + } + + companion object { + private const val STATUS_BAR_WIDTH = 100 + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt index 58396e7cef82..8aa8a50afcd4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt @@ -22,8 +22,6 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher -import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractorImpl.NotificationElement -import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractorImpl.QSElement import com.android.systemui.shade.shadeTestUtil import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -52,7 +50,7 @@ class ShadeExpandedStateInteractorTest : SysuiTestCase() { val element = currentlyExpandedElement.value - assertThat(element).isInstanceOf(QSElement::class.java) + assertThat(element).isInstanceOf(QSShadeElement::class.java) } @Test @@ -62,7 +60,7 @@ class ShadeExpandedStateInteractorTest : SysuiTestCase() { val element = underTest.currentlyExpandedElement.value - assertThat(element).isInstanceOf(NotificationElement::class.java) + assertThat(element).isInstanceOf(NotificationShadeElement::class.java) } @Test diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt index 17b5e5b584b4..d53f9f7ec595 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt @@ -16,6 +16,7 @@ package com.android.systemui.shade.display +import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement import dagger.Binds import dagger.Module import dagger.multibindings.IntoSet @@ -33,11 +34,33 @@ interface ShadeDisplayPolicy { val displayId: StateFlow<Int> } +/** Return the latest element the user intended to expand in the shade (notifications or QS). */ +interface ShadeExpansionIntent { + /** + * Returns the latest element the user intended to expand in the shade (notifications or QS). + * + * When the shade moves to a different display (e.g., due to a touch on the status bar of an + * external display), it's first collapsed and then re-expanded on the target display. + * + * If the user was trying to open a specific element (QS or notifications) when the shade was on + * the original display, that intention might be lost during the collapse/re-expand transition. + * This is used to preserve the user's intention, ensuring the correct element is expanded on + * the target display. + * + * Note that the expansion intent is kept for a very short amount of time (ideally, just a bit + * above the time it takes for the shade to collapse) + */ + fun consumeExpansionIntent(): ShadeElement? +} + @Module interface ShadeDisplayPolicyModule { @Binds fun provideDefaultPolicy(impl: StatusBarTouchShadeDisplayPolicy): ShadeDisplayPolicy + @Binds + fun provideShadeExpansionIntent(impl: StatusBarTouchShadeDisplayPolicy): ShadeExpansionIntent + @IntoSet @Binds fun provideDefaultDisplayPolicyToSet(impl: DefaultDisplayShadePolicy): ShadeDisplayPolicy diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt index 30b086f03d66..91020aa7bdb0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt @@ -18,16 +18,25 @@ package com.android.systemui.shade.display import android.util.Log import android.view.Display +import android.view.MotionEvent import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked +import com.android.systemui.shade.domain.interactor.NotificationShadeElement +import com.android.systemui.shade.domain.interactor.QSShadeElement +import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround +import dagger.Lazy +import java.util.concurrent.atomic.AtomicReference import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -49,14 +58,20 @@ class StatusBarTouchShadeDisplayPolicy constructor( displayRepository: DisplayRepository, keyguardRepository: KeyguardRepository, - @Background val backgroundScope: CoroutineScope, - @ShadeOnDefaultDisplayWhenLocked val shadeOnDefaultDisplayWhenLocked: Boolean, -) : ShadeDisplayPolicy { + @Background private val backgroundScope: CoroutineScope, + @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean, + private val shadeInteractor: Lazy<ShadeInteractor>, + private val qsShadeElement: Lazy<QSShadeElement>, + private val notificationElement: Lazy<NotificationShadeElement>, +) : ShadeDisplayPolicy, ShadeExpansionIntent { override val name: String = "status_bar_latest_touch" private val currentDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY) private val availableDisplayIds: StateFlow<Set<Int>> = displayRepository.displayIds + private var latestIntent = AtomicReference<ShadeElement?>() + private var timeoutJob: Job? = null + override val displayId: StateFlow<Int> = if (shadeOnDefaultDisplayWhenLocked) { keyguardRepository.isKeyguardShowing @@ -75,8 +90,29 @@ constructor( private var removalListener: Job? = null /** Called when the status bar on the given display is touched. */ - fun onStatusBarTouched(statusBarDisplayId: Int) { + fun onStatusBarTouched(event: MotionEvent, statusBarWidth: Int) { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() + updateShadeDisplayIfNeeded(event) + updateExpansionIntent(event, statusBarWidth) + } + + override fun consumeExpansionIntent(): ShadeElement? { + return latestIntent.getAndSet(null) + } + + private fun updateExpansionIntent(event: MotionEvent, statusBarWidth: Int) { + val element = classifyStatusBarEvent(event, statusBarWidth) + latestIntent.set(element) + timeoutJob?.cancel() + timeoutJob = + backgroundScope.launchTraced("StatusBarTouchDisplayPolicy#intentTimeout") { + delay(EXPANSION_INTENT_EXPIRY) + latestIntent.set(null) + } + } + + private fun updateShadeDisplayIfNeeded(event: MotionEvent) { + val statusBarDisplayId = event.displayId if (statusBarDisplayId !in availableDisplayIds.value) { Log.e(TAG, "Got touch on unknown display $statusBarDisplayId") return @@ -90,6 +126,17 @@ constructor( } } + private fun classifyStatusBarEvent( + motionEvent: MotionEvent, + statusbarWidth: Int, + ): ShadeElement { + val xPercentage = motionEvent.x / statusbarWidth + val threshold = shadeInteractor.get().getTopEdgeSplitFraction() + return if (xPercentage < threshold) { + notificationElement.get() + } else qsShadeElement.get() + } + private fun monitorDisplayRemovals(): Job { return backgroundScope.launchTraced("StatusBarTouchDisplayPolicy#monitorDisplayRemovals") { currentDisplayId.subscriptionCount @@ -112,5 +159,6 @@ constructor( private companion object { const val TAG = "StatusBarTouchDisplayPolicy" + val EXPANSION_INTENT_EXPIRY = 2.seconds } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt index 691a383cb338..f67d33122063 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt @@ -30,6 +30,7 @@ import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo import com.android.systemui.shade.ShadeTraceLogger.traceReparenting import com.android.systemui.shade.data.repository.ShadeDisplaysRepository +import com.android.systemui.shade.display.ShadeExpansionIntent import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.window.flags.Flags import java.util.Optional @@ -49,6 +50,7 @@ constructor( @Main private val mainThreadContext: CoroutineContext, private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker, shadeExpandedInteractor: Optional<ShadeExpandedStateInteractor>, + private val shadeExpansionIntent: ShadeExpansionIntent, ) : CoreStartable { private val shadeExpandedInteractor = @@ -90,10 +92,7 @@ constructor( withContext(mainThreadContext) { traceReparenting { shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId) - val expandedElement = shadeExpandedInteractor.currentlyExpandedElement.value - expandedElement?.collapse(reason = "Shade window move") - reparentToDisplayId(id = destinationId) - expandedElement?.expand(reason = "Shade window move") + collapseAndExpandShadeIfNeeded { reparentToDisplayId(id = destinationId) } checkContextDisplayMatchesExpected(destinationId) } } @@ -106,6 +105,18 @@ constructor( } } + private suspend fun collapseAndExpandShadeIfNeeded(wrapped: () -> Unit) { + val previouslyExpandedElement = shadeExpandedInteractor.currentlyExpandedElement.value + previouslyExpandedElement?.collapse(reason = COLLAPSE_EXPAND_REASON) + + wrapped() + + // If the user was trying to expand a specific shade element, let's make sure to expand + // that one. Otherwise, we can just re-expand the previous expanded element. + shadeExpansionIntent.consumeExpansionIntent()?.expand(COLLAPSE_EXPAND_REASON) + ?: previouslyExpandedElement?.expand(reason = COLLAPSE_EXPAND_REASON) + } + private fun checkContextDisplayMatchesExpected(destinationId: Int) { if (shadeContext.displayId != destinationId) { Log.wtf( @@ -125,5 +136,6 @@ constructor( private companion object { const val TAG = "ShadeDisplaysInteractor" + const val COLLAPSE_EXPAND_REASON = "Shade window move" } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt index dd3abeec5a72..c1ea71e8e757 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.util.kotlin.Utils.Companion.combineState import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -47,7 +48,7 @@ interface ShadeExpandedStateInteractor { val currentlyExpandedElement: StateFlow<ShadeElement?> /** An element from the shade window that can be expanded or collapsed. */ - abstract class ShadeElement { + sealed class ShadeElement { /** Expands the shade element, returning when the expansion is done */ abstract suspend fun expand(reason: String) @@ -60,13 +61,12 @@ interface ShadeExpandedStateInteractor { class ShadeExpandedStateInteractorImpl @Inject constructor( - private val shadeInteractor: ShadeInteractor, + shadeInteractor: ShadeInteractor, @Background private val bgScope: CoroutineScope, + private val notificationElement: NotificationShadeElement, + private val qsElement: QSShadeElement, ) : ShadeExpandedStateInteractor { - private val notificationElement = NotificationElement() - private val qsElement = QSElement() - override val currentlyExpandedElement: StateFlow<ShadeElement?> = if (SceneContainerFlag.isEnabled) { combineState( @@ -84,35 +84,47 @@ constructor( } else { MutableStateFlow(null) } +} - inner class NotificationElement : ShadeElement() { - override suspend fun expand(reason: String) { - shadeInteractor.expandNotificationsShade(reason) - shadeInteractor.shadeExpansion.waitUntil(1f) - } +private suspend fun StateFlow<Float>.waitUntil(f: Float, coroutineContext: CoroutineContext) { + // it's important to not do this in the main thread otherwise it will block any rendering. + withContext(coroutineContext) { + withTimeout(1.seconds) { traceWaitForExpansion(expansion = f) { first { it == f } } } + } +} - override suspend fun collapse(reason: String) { - shadeInteractor.collapseNotificationsShade(reason) - shadeInteractor.shadeExpansion.waitUntil(0f) - } +@SysUISingleton +class NotificationShadeElement +@Inject +constructor( + private val shadeInteractor: ShadeInteractor, + @Background private val bgContext: CoroutineContext, +) : ShadeElement() { + override suspend fun expand(reason: String) { + shadeInteractor.expandNotificationsShade(reason) + shadeInteractor.shadeExpansion.waitUntil(1f, bgContext) } - inner class QSElement : ShadeElement() { - override suspend fun expand(reason: String) { - shadeInteractor.expandQuickSettingsShade(reason) - shadeInteractor.qsExpansion.waitUntil(1f) - } + override suspend fun collapse(reason: String) { + shadeInteractor.collapseNotificationsShade(reason) + shadeInteractor.shadeExpansion.waitUntil(0f, bgContext) + } +} - override suspend fun collapse(reason: String) { - shadeInteractor.collapseQuickSettingsShade(reason) - shadeInteractor.qsExpansion.waitUntil(0f) - } +@SysUISingleton +class QSShadeElement +@Inject +constructor( + private val shadeInteractor: ShadeInteractor, + @Background private val bgContext: CoroutineContext, +) : ShadeElement() { + override suspend fun expand(reason: String) { + shadeInteractor.expandQuickSettingsShade(reason) + shadeInteractor.qsExpansion.waitUntil(1f, bgContext) } - private suspend fun StateFlow<Float>.waitUntil(f: Float) { - // it's important to not do this in the main thread otherwise it will block any rendering. - withContext(bgScope.coroutineContext) { - withTimeout(1.seconds) { traceWaitForExpansion(expansion = f) { first { it == f } } } - } + override suspend fun collapse(reason: String) { + shadeInteractor.collapseQuickSettingsShade(reason) + shadeInteractor.qsExpansion.waitUntil(0f, bgContext) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index aa1308931f99..3f44f7bdef90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -234,7 +234,7 @@ private constructor( ) } if (ShadeWindowGoesAround.isEnabled && event.action == MotionEvent.ACTION_DOWN) { - lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(context.displayId) + lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(event, mView.width) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 243be3dc142d..1f9ed3c0c939 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -62,7 +62,6 @@ import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel -import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.whenever import com.android.systemui.util.view.ViewUtil @@ -74,7 +73,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.never @@ -82,6 +80,8 @@ import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.eq @SmallTest @RunWith(AndroidJUnit4::class) @@ -443,25 +443,28 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { @Test @EnableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND) fun onTouch_actionDown_propagatesToDisplayPolicy() { - controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + controller.onTouch(event) - verify(statusBarTouchShadeDisplayPolicy).onStatusBarTouched(eq(mContext.displayId)) + verify(statusBarTouchShadeDisplayPolicy).onStatusBarTouched(eq(event), any()) } @Test @EnableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND) fun onTouch_actionUp_notPropagatesToDisplayPolicy() { - controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)) + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0) + controller.onTouch(event) - verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any()) + verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any(), any()) } @Test @DisableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND) fun onTouch_shadeWindowGoesAroundDisabled_notPropagatesToDisplayPolicy() { - controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + controller.onTouch(event) - verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any()) + verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(eq(event), any()) } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt index 636cb37adf03..aaef27d257c5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt @@ -23,7 +23,11 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.shade.display.AnyExternalShadeDisplayPolicy import com.android.systemui.shade.display.DefaultDisplayShadePolicy import com.android.systemui.shade.display.ShadeDisplayPolicy +import com.android.systemui.shade.display.ShadeExpansionIntent import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy +import com.android.systemui.shade.domain.interactor.notificationElement +import com.android.systemui.shade.domain.interactor.qsElement +import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.util.settings.fakeGlobalSettings val Kosmos.defaultShadeDisplayPolicy: DefaultDisplayShadePolicy by @@ -37,16 +41,20 @@ val Kosmos.anyExternalShadeDisplayPolicy: AnyExternalShadeDisplayPolicy by ) } -val Kosmos.focusBasedShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by +val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by Kosmos.Fixture { StatusBarTouchShadeDisplayPolicy( displayRepository = displayRepository, backgroundScope = testScope.backgroundScope, keyguardRepository = keyguardRepository, shadeOnDefaultDisplayWhenLocked = false, + shadeInteractor = { shadeInteractor }, + notificationElement = { notificationElement }, + qsShadeElement = { qsElement }, ) } - +val Kosmos.shadeExpansionIntent: ShadeExpansionIntent by + Kosmos.Fixture { statusBarTouchShadeDisplayPolicy } val Kosmos.shadeDisplaysRepository: MutableShadeDisplaysRepository by Kosmos.Fixture { ShadeDisplaysRepositoryImpl( @@ -62,7 +70,7 @@ val Kosmos.shadeDisplayPolicies: Set<ShadeDisplayPolicy> by setOf( defaultShadeDisplayPolicy, anyExternalShadeDisplayPolicy, - focusBasedShadeDisplayPolicy, + statusBarTouchShadeDisplayPolicy, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt index 6e44df833582..923de2dcbf68 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt @@ -23,6 +23,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeWindowLayoutParams import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository +import com.android.systemui.shade.data.repository.shadeExpansionIntent import java.util.Optional import org.mockito.kotlin.any import org.mockito.kotlin.mock @@ -49,5 +50,6 @@ val Kosmos.shadeDisplaysInteractor by testScope.backgroundScope.coroutineContext, mockedShadeDisplayChangeLatencyTracker, Optional.of(shadeExpandedStateInteractor), + shadeExpansionIntent, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt index 1dc7229a6506..32a30502a370 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt @@ -31,7 +31,6 @@ import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.policy.data.repository.userSetupRepository import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor import com.android.systemui.user.domain.interactor.userSwitcherInteractor -import org.mockito.kotlin.mock var Kosmos.baseShadeInteractor: BaseShadeInteractor by Kosmos.Fixture { @@ -73,7 +72,19 @@ val Kosmos.shadeInteractorImpl by shadeModeInteractor = shadeModeInteractor, ) } -var Kosmos.mockShadeInteractor: ShadeInteractor by Kosmos.Fixture { mock() } +var Kosmos.notificationElement: NotificationShadeElement by + Kosmos.Fixture { + NotificationShadeElement(shadeInteractor, testScope.backgroundScope.coroutineContext) + } +var Kosmos.qsElement: QSShadeElement by + Kosmos.Fixture { QSShadeElement(shadeInteractor, testScope.backgroundScope.coroutineContext) } val Kosmos.shadeExpandedStateInteractor by - Kosmos.Fixture { ShadeExpandedStateInteractorImpl(shadeInteractor, testScope.backgroundScope) } + Kosmos.Fixture { + ShadeExpandedStateInteractorImpl( + shadeInteractor, + testScope.backgroundScope, + notificationElement, + qsElement, + ) + } val Kosmos.fakeShadeExpandedStateInteractor by Kosmos.Fixture { FakeShadeExpandedStateInteractor() } |