summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt77
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeExpandedStateInteractor.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt25
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt6
12 files changed, 317 insertions, 17 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
index a98d1a2ea4a5..d3ba3dceb4cf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -22,10 +22,13 @@ import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.scene.ui.view.mockShadeRootView
import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
import com.android.systemui.testKosmos
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,6 +44,7 @@ import org.mockito.kotlin.whenever
class ShadeDisplaysInteractorTest : SysuiTestCase() {
val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val testScope = kosmos.testScope
private val shadeRootview = kosmos.mockShadeRootView
private val positionRepository = kosmos.fakeShadeDisplaysRepository
private val shadeContext = kosmos.mockedWindowContext
@@ -49,7 +53,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
private val configuration = mock<Configuration>()
private val display = mock<Display>()
- private val underTest = kosmos.shadeDisplaysInteractor
+ private val underTest by lazy { kosmos.shadeDisplaysInteractor }
@Before
fun setup() {
@@ -84,12 +88,14 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
}
@Test
- fun start_shadeInWrongPosition_logsStartToLatencyTracker() {
- whenever(display.displayId).thenReturn(0)
- positionRepository.setDisplayId(1)
+ fun start_shadeInWrongPosition_logsStartToLatencyTracker() =
+ testScope.runTest {
+ whenever(display.displayId).thenReturn(0)
+ positionRepository.setDisplayId(1)
- underTest.start()
+ underTest.start()
+ advanceUntilIdle()
- verify(latencyTracker).onShadeDisplayChanging(eq(1))
- }
+ verify(latencyTracker).onShadeDisplayChanging(eq(1))
+ }
}
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
new file mode 100644
index 000000000000..58396e7cef82
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2025 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.shade.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+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
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+@EnableSceneContainer
+class ShadeExpandedStateInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val testScope = kosmos.testScope
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
+
+ private val underTest: ShadeExpandedStateInteractor by lazy {
+ kosmos.shadeExpandedStateInteractor
+ }
+
+ @Test
+ fun expandedElement_qsExpanded_returnsQSElement() =
+ testScope.runTest {
+ shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0f, qsExpansion = 1f)
+ val currentlyExpandedElement = underTest.currentlyExpandedElement
+
+ val element = currentlyExpandedElement.value
+
+ assertThat(element).isInstanceOf(QSElement::class.java)
+ }
+
+ @Test
+ fun expandedElement_shadeExpanded_returnsShade() =
+ testScope.runTest {
+ shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 1f, qsExpansion = 0f)
+
+ val element = underTest.currentlyExpandedElement.value
+
+ assertThat(element).isInstanceOf(NotificationElement::class.java)
+ }
+
+ @Test
+ fun expandedElement_noneExpanded_returnsNull() =
+ testScope.runTest {
+ shadeTestUtil.setShadeAndQsExpansion(shadeExpansion = 0f, qsExpansion = 0f)
+
+ val element = underTest.currentlyExpandedElement.value
+
+ assertThat(element).isNull()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index 63e8ba8f65cd..747642097327 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -37,12 +37,13 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
-import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
-import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
import com.android.systemui.shade.display.ShadeDisplayPolicyModule
+import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
+import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.ConfigurationForwarder
@@ -276,6 +277,8 @@ object ShadeDisplayAwareModule {
@Module
internal interface OptionalShadeDisplayAwareBindings {
@BindsOptionalOf fun bindOptionalOfWindowRootView(): WindowRootView
+
+ @BindsOptionalOf fun bindOptionalOShadeExpandedStateInteractor(): ShadeExpandedStateInteractor
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 2348a110eb3a..b9df9f868dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -35,6 +35,8 @@ import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLega
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorSceneContainerImpl
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractorImpl
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl
@@ -176,4 +178,10 @@ abstract class ShadeModule {
@Binds
@SysUISingleton
abstract fun bindShadeModeInteractor(impl: ShadeModeInteractorImpl): ShadeModeInteractor
+
+ @Binds
+ @SysUISingleton
+ abstract fun bindShadeExpandedStateInteractor(
+ impl: ShadeExpandedStateInteractorImpl
+ ): ShadeExpandedStateInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt
index 11805992fd6a..9a9fc467c53f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt
@@ -27,7 +27,7 @@ import com.android.app.tracing.coroutines.TrackTracer
* them across various threads' logs.
*/
object ShadeTraceLogger {
- private val t = TrackTracer(trackName = "ShadeTraceLogger", trackGroup = "shade")
+ val t = TrackTracer(trackName = "ShadeTraceLogger", trackGroup = "shade")
@JvmStatic
fun logOnMovedToDisplay(displayId: Int, config: Configuration) {
@@ -44,8 +44,11 @@ object ShadeTraceLogger {
t.instant { "moveShadeWindowTo(displayId=$displayId)" }
}
- @JvmStatic
- fun traceReparenting(r: () -> Unit) {
+ suspend fun traceReparenting(r: suspend () -> Unit) {
t.traceAsync({ "reparenting" }) { r() }
}
+
+ inline fun traceWaitForExpansion(expansion: Float, r: () -> Unit) {
+ t.traceAsync({ "waiting for shade expansion to match $expansion" }) { r() }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeExpandedStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeExpandedStateInteractor.kt
new file mode 100644
index 000000000000..eab00166c8ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeExpandedStateInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2025 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.shade.domain.interactor
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Fake [ShadeExpandedStateInteractor] for tests. */
+class FakeShadeExpandedStateInteractor : ShadeExpandedStateInteractor {
+
+ private val mutableExpandedElement =
+ MutableStateFlow<ShadeExpandedStateInteractor.ShadeElement?>(null)
+ override val currentlyExpandedElement: StateFlow<ShadeExpandedStateInteractor.ShadeElement?>
+ get() = mutableExpandedElement
+
+ fun setState(state: ShadeExpandedStateInteractor.ShadeElement?) {
+ mutableExpandedElement.value = state
+ }
+}
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 be561b178136..691a383cb338 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
@@ -32,6 +32,7 @@ import com.android.systemui.shade.ShadeTraceLogger.traceReparenting
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.window.flags.Flags
+import java.util.Optional
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
@@ -47,8 +48,19 @@ constructor(
@Background private val bgScope: CoroutineScope,
@Main private val mainThreadContext: CoroutineContext,
private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker,
+ shadeExpandedInteractor: Optional<ShadeExpandedStateInteractor>,
) : CoreStartable {
+ private val shadeExpandedInteractor =
+ shadeExpandedInteractor.orElse(null)
+ ?: error(
+ """
+ ShadeExpandedStateInteractor must be provided for ShadeDisplaysInteractor to work.
+ If it is not, it means this is being instantiated in a SystemUI variant that shouldn't.
+ """
+ .trimIndent()
+ )
+
override fun start() {
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
bgScope.launchTraced(TAG) {
@@ -78,9 +90,12 @@ 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")
+ checkContextDisplayMatchesExpected(destinationId)
}
- checkContextDisplayMatchesExpected(destinationId)
}
} catch (e: IllegalStateException) {
Log.e(
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
new file mode 100644
index 000000000000..dd3abeec5a72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2025 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.shade.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeTraceLogger.traceWaitForExpansion
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.util.kotlin.Utils.Companion.combineState
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeout
+
+/**
+ * Wrapper around [ShadeInteractor] to facilitate expansion and collapse of Notifications and quick
+ * settings.
+ *
+ * Specifially created to simplify [ShadeDisplaysInteractor] logic.
+ *
+ * NOTE: with [SceneContainerFlag] or [DualShade] disabled, [currentlyExpandedElement] will always
+ * return null!
+ */
+interface ShadeExpandedStateInteractor {
+ /** Returns the expanded [ShadeElement]. If none is, returns null. */
+ val currentlyExpandedElement: StateFlow<ShadeElement?>
+
+ /** An element from the shade window that can be expanded or collapsed. */
+ abstract class ShadeElement {
+ /** Expands the shade element, returning when the expansion is done */
+ abstract suspend fun expand(reason: String)
+
+ /** Collapses the shade element, returning when the collapse is done. */
+ abstract suspend fun collapse(reason: String)
+ }
+}
+
+@SysUISingleton
+class ShadeExpandedStateInteractorImpl
+@Inject
+constructor(
+ private val shadeInteractor: ShadeInteractor,
+ @Background private val bgScope: CoroutineScope,
+) : ShadeExpandedStateInteractor {
+
+ private val notificationElement = NotificationElement()
+ private val qsElement = QSElement()
+
+ override val currentlyExpandedElement: StateFlow<ShadeElement?> =
+ if (SceneContainerFlag.isEnabled) {
+ combineState(
+ shadeInteractor.isShadeAnyExpanded,
+ shadeInteractor.isQsExpanded,
+ bgScope,
+ SharingStarted.Eagerly,
+ ) { isShadeAnyExpanded, isQsExpanded ->
+ when {
+ isShadeAnyExpanded -> notificationElement
+ isQsExpanded -> qsElement
+ else -> null
+ }
+ }
+ } else {
+ MutableStateFlow(null)
+ }
+
+ inner class NotificationElement : ShadeElement() {
+ override suspend fun expand(reason: String) {
+ shadeInteractor.expandNotificationsShade(reason)
+ shadeInteractor.shadeExpansion.waitUntil(1f)
+ }
+
+ override suspend fun collapse(reason: String) {
+ shadeInteractor.collapseNotificationsShade(reason)
+ shadeInteractor.shadeExpansion.waitUntil(0f)
+ }
+ }
+
+ inner class QSElement : ShadeElement() {
+ override suspend fun expand(reason: String) {
+ shadeInteractor.expandQuickSettingsShade(reason)
+ shadeInteractor.qsExpansion.waitUntil(1f)
+ }
+
+ override suspend fun collapse(reason: String) {
+ shadeInteractor.collapseQuickSettingsShade(reason)
+ shadeInteractor.qsExpansion.waitUntil(0f)
+ }
+ }
+
+ 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 } } }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
index d9a2e956cc86..a88b127ae157 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
@@ -17,10 +17,14 @@
package com.android.systemui.util.kotlin
import android.content.Context
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
class Utils {
companion object {
@@ -32,6 +36,7 @@ class Utils {
fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
Quad(a, bcd.first, bcd.second, bcd.third)
+
fun <A, B, C, D> toQuad(abc: Triple<A, B, C>, d: D) =
Quad(abc.first, abc.second, abc.third, d)
@@ -51,7 +56,7 @@ class Utils {
bcdefg.third,
bcdefg.fourth,
bcdefg.fifth,
- bcdefg.sixth
+ bcdefg.sixth,
)
/**
@@ -81,7 +86,7 @@ class Utils {
fun <A, B, C, D> Flow<A>.sample(
b: Flow<B>,
c: Flow<C>,
- d: Flow<D>
+ d: Flow<D>,
): Flow<Quad<A, B, C, D>> {
return this.sample(combine(b, c, d, ::Triple), ::toQuad)
}
@@ -134,6 +139,20 @@ class Utils {
): Flow<Septuple<A, B, C, D, E, F, G>> {
return this.sample(combine(b, c, d, e, f, g, ::Sextuple), ::toSeptuple)
}
+
+ /**
+ * Combines 2 state flows, applying [transform] between the initial values to set the
+ * initial value of the resulting StateFlow.
+ */
+ fun <A, B, R> combineState(
+ f1: StateFlow<A>,
+ f2: StateFlow<B>,
+ scope: CoroutineScope,
+ sharingStarted: SharingStarted,
+ transform: (A, B) -> R,
+ ): StateFlow<R> =
+ combine(f1, f2) { a, b -> transform(a, b) }
+ .stateIn(scope, sharingStarted, transform(f1.value, f2.value))
}
}
@@ -144,7 +163,7 @@ data class Quint<A, B, C, D, E>(
val second: B,
val third: C,
val fourth: D,
- val fifth: E
+ val fifth: E,
)
data class Sextuple<A, B, C, D, E, F>(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
index ab193d294b8c..b3d89dbb834d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
@@ -203,6 +203,7 @@ class ShadeTestUtilSceneImpl(
val isUserInputOngoing = MutableStateFlow(true)
override fun setShadeAndQsExpansion(shadeExpansion: Float, qsExpansion: Float) {
+ shadeRepository.setLegacyIsQsExpanded(qsExpansion > 0f)
if (shadeExpansion == 1f) {
setIdleScene(Scenes.Shade)
} else if (qsExpansion == 1f) {
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 4af5e7d9d725..6e44df833582 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,11 +23,21 @@ 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 java.util.Optional
+import org.mockito.kotlin.any
import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
val Kosmos.shadeLayoutParams by Kosmos.Fixture { ShadeWindowLayoutParams.create(mockedContext) }
-val Kosmos.mockedWindowContext by Kosmos.Fixture { mock<WindowContext>() }
+val Kosmos.mockedWindowContext by
+ Kosmos.Fixture {
+ mock<WindowContext>().apply {
+ whenever(reparentToDisplay(any())).thenAnswer { displayIdParam ->
+ whenever(displayId).thenReturn(displayIdParam.arguments[0] as Int)
+ }
+ }
+ }
val Kosmos.mockedShadeDisplayChangeLatencyTracker by
Kosmos.Fixture { mock<ShadeDisplayChangeLatencyTracker>() }
val Kosmos.shadeDisplaysInteractor by
@@ -38,5 +48,6 @@ val Kosmos.shadeDisplaysInteractor by
testScope.backgroundScope,
testScope.backgroundScope.coroutineContext,
mockedShadeDisplayChangeLatencyTracker,
+ Optional.of(shadeExpandedStateInteractor),
)
}
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 af6d6249b4a8..1dc7229a6506 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
@@ -21,6 +21,7 @@ import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.ShadeModule
@@ -30,6 +31,7 @@ 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 {
@@ -71,3 +73,7 @@ val Kosmos.shadeInteractorImpl by
shadeModeInteractor = shadeModeInteractor,
)
}
+var Kosmos.mockShadeInteractor: ShadeInteractor by Kosmos.Fixture { mock() }
+val Kosmos.shadeExpandedStateInteractor by
+ Kosmos.Fixture { ShadeExpandedStateInteractorImpl(shadeInteractor, testScope.backgroundScope) }
+val Kosmos.fakeShadeExpandedStateInteractor by Kosmos.Fixture { FakeShadeExpandedStateInteractor() }