summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt160
3 files changed, 100 insertions, 78 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
index 7bca86e2e8fb..12be32c54b22 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -31,8 +31,10 @@ import com.android.systemui.statusbar.policy.onThemeChanged
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.view.bindLatest
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -95,7 +97,8 @@ constructor(
* call [onInflate] on the resulting view each time. Disposes of the [DisposableHandle] returned by
* [onInflate] when done.
*
- * This never completes unless cancelled, it just suspends and waits for updates.
+ * This never completes unless cancelled, it just suspends and waits for updates. It runs on a
+ * background thread using [backgroundDispatcher].
*
* For parameters [resource], [root] and [attachToRoot], see [LayoutInflater.inflate].
*
@@ -105,7 +108,7 @@ constructor(
* ```
* parentView.repeatWhenAttached {
* configurationState
- * .reinflateOnChange(
+ * .reinflateAndBindLatest(
* R.layout.my_layout,
* parentView,
* attachToRoot = false,
@@ -124,7 +127,10 @@ suspend fun <T : View> ConfigurationState.reinflateAndBindLatest(
@LayoutRes resource: Int,
root: ViewGroup?,
attachToRoot: Boolean,
+ backgroundDispatcher: CoroutineDispatcher,
onInflate: (T) -> DisposableHandle?,
) {
- inflateLayout<T>(resource, root, attachToRoot).bindLatest(onInflate)
+ inflateLayout<T>(resource, root, attachToRoot)
+ .flowOn(backgroundDispatcher)
+ .bindLatest(onInflate)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 4554085c35c0..fdda1205c84c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -24,6 +24,7 @@ import com.android.internal.logging.nano.MetricsProto
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.reinflateAndBindLatest
import com.android.systemui.common.ui.view.setImportantForAccessibilityYesNo
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
@@ -40,6 +41,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.Notificati
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -48,12 +50,13 @@ class NotificationListViewBinder
@Inject
constructor(
private val viewModel: NotificationListViewModel,
- private val metricsLogger: MetricsLogger,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val configuration: ConfigurationState,
private val configurationController: ConfigurationController,
private val falsingManager: FalsingManager,
private val iconAreaController: NotificationIconAreaController,
private val iconViewBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
+ private val metricsLogger: MetricsLogger,
private val shelfIconViewStore: ShelfNotificationIconViewStore,
) {
@@ -101,6 +104,7 @@ constructor(
R.layout.status_bar_notification_footer,
parentView,
attachToRoot = false,
+ backgroundDispatcher,
) { footerView: FooterView ->
traceSection("bind FooterView") {
val disposableHandle =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
index 034b8022305a..112cec25784c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/ConfigurationStateTest.kt
@@ -30,6 +30,8 @@ import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -44,102 +46,112 @@ class ConfigurationStateTest : SysuiTestCase() {
private val configurationController: ConfigurationController = mock()
private val layoutInflater = TestLayoutInflater()
+ private val backgroundDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(backgroundDispatcher)
val underTest = ConfigurationState(configurationController, context, layoutInflater)
@Test
- fun reinflateAndBindLatest_inflatesWithoutEmission() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_inflatesWithoutEmission() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- // Inflates without an emission
- runCurrent()
- assertThat(layoutInflater.inflationCount).isEqualTo(1)
- assertThat(callbackCount).isEqualTo(1)
- }
+ // Inflates without an emission
+ runCurrent()
+ assertThat(layoutInflater.inflationCount).isEqualTo(1)
+ assertThat(callbackCount).isEqualTo(1)
+ }
@Test
- fun reinflateAndBindLatest_reinflatesOnThemeChanged() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_reinflatesOnThemeChanged() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- runCurrent()
+ runCurrent()
- val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
- verify(configurationController, atLeastOnce()).addCallback(capture())
- }
+ val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
+ verify(configurationController, atLeastOnce()).addCallback(capture())
+ }
- listOf(1, 2, 3).forEach { count ->
- assertThat(layoutInflater.inflationCount).isEqualTo(count)
- assertThat(callbackCount).isEqualTo(count)
- configListeners.forEach { it.onThemeChanged() }
- runCurrent()
+ listOf(1, 2, 3).forEach { count ->
+ assertThat(layoutInflater.inflationCount).isEqualTo(count)
+ assertThat(callbackCount).isEqualTo(count)
+ configListeners.forEach { it.onThemeChanged() }
+ runCurrent()
+ }
}
- }
@Test
- fun reinflateAndBindLatest_reinflatesOnDensityOrFontScaleChanged() = runTest {
- var callbackCount = 0
- backgroundScope.launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- null
+ fun reinflateAndBindLatest_reinflatesOnDensityOrFontScaleChanged() =
+ testScope.runTest {
+ var callbackCount = 0
+ backgroundScope.launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ null
+ }
}
- }
- runCurrent()
+ runCurrent()
- val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
- verify(configurationController, atLeastOnce()).addCallback(capture())
- }
+ val configListeners: List<ConfigurationController.ConfigurationListener> = captureMany {
+ verify(configurationController, atLeastOnce()).addCallback(capture())
+ }
- listOf(1, 2, 3).forEach { count ->
- assertThat(layoutInflater.inflationCount).isEqualTo(count)
- assertThat(callbackCount).isEqualTo(count)
- configListeners.forEach { it.onDensityOrFontScaleChanged() }
- runCurrent()
+ listOf(1, 2, 3).forEach { count ->
+ assertThat(layoutInflater.inflationCount).isEqualTo(count)
+ assertThat(callbackCount).isEqualTo(count)
+ configListeners.forEach { it.onDensityOrFontScaleChanged() }
+ runCurrent()
+ }
}
- }
@Test
- fun testReinflateAndBindLatest_disposesOnCancel() = runTest {
- var callbackCount = 0
- var disposed = false
- val job = launch {
- underTest.reinflateAndBindLatest<View>(
- resource = 0,
- root = null,
- attachToRoot = false,
- ) {
- callbackCount++
- DisposableHandle { disposed = true }
+ fun testReinflateAndBindLatest_disposesOnCancel() =
+ testScope.runTest {
+ var callbackCount = 0
+ var disposed = false
+ val job = launch {
+ underTest.reinflateAndBindLatest<View>(
+ resource = 0,
+ root = null,
+ attachToRoot = false,
+ backgroundDispatcher,
+ ) {
+ callbackCount++
+ DisposableHandle { disposed = true }
+ }
}
- }
- runCurrent()
- job.cancelAndJoin()
- assertThat(disposed).isTrue()
- }
+ runCurrent()
+ job.cancelAndJoin()
+ assertThat(disposed).isTrue()
+ }
inner class TestLayoutInflater : LayoutInflater(context) {