Introduce NICViewModel#iconColors
This CL replaces the older tint calculation logic used for AOD and
status bar notification icons with a new Recommended Architecture stack.
Flag: NOTIFICATION_ICON_CONTAINER_REFACTOR
Bug: 290787599
Bug: 278765923
Test: atest SystemUITests
Change-Id: Ie8cf64c103e5e4fa99dc499a3eaa8bd18ab6f609
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index a9d2ee3..403c7c5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -19,7 +19,6 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.view.View;
-import android.widget.ImageView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.annotations.DependsOn;
@@ -51,21 +50,11 @@
void addDarkReceiver(DarkReceiver receiver);
/**
- * Adds a receiver to receive callbacks onDarkChanged
- */
- void addDarkReceiver(ImageView imageView);
-
- /**
* Must have been previously been added through one of the addDarkReceive methods above.
*/
void removeDarkReceiver(DarkReceiver object);
/**
- * Must have been previously been added through one of the addDarkReceive methods above.
- */
- void removeDarkReceiver(ImageView object);
-
- /**
* Used to reapply darkness on an object, must have previously been added through
* addDarkReceiver.
*/
@@ -104,8 +93,8 @@
}
/**
- * @return true if more than half of the view area are in any of the given
- * areas, false otherwise
+ * @return true if more than half of the view's area is in any of the given area Rects, false
+ * otherwise
*/
static boolean isInAreas(Collection<Rect> areas, View view) {
if (areas.isEmpty()) {
@@ -120,9 +109,40 @@
}
/**
- * @return true if more than half of the view area are in area, false
+ * @return true if more than half of the viewBounds are in any of the given area Rects, false
* otherwise
*/
+ static boolean isInAreas(Collection<Rect> areas, Rect viewBounds) {
+ if (areas.isEmpty()) {
+ return true;
+ }
+ for (Rect area : areas) {
+ if (isInArea(area, viewBounds)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** @return true if more than half of the viewBounds are in the area Rect, false otherwise */
+ static boolean isInArea(Rect area, Rect viewBounds) {
+ if (area.isEmpty()) {
+ return true;
+ }
+ sTmpRect.set(area);
+ int left = viewBounds.left;
+ int width = viewBounds.width();
+
+ int intersectStart = Math.max(left, area.left);
+ int intersectEnd = Math.min(left + width, area.right);
+ int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+ boolean coversFullStatusBar = area.top <= 0;
+ boolean majorityOfWidth = 2 * intersectAmount > width;
+ return majorityOfWidth && coversFullStatusBar;
+ }
+
+ /** @return true if more than half of the view's area is in the area Rect, false otherwise */
static boolean isInArea(Rect area, View view) {
if (area.isEmpty()) {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
new file mode 100644
index 0000000..8d5b84f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.common.ui
+
+import android.content.Context
+import androidx.annotation.AttrRes
+import androidx.annotation.ColorInt
+import androidx.annotation.DimenRes
+import com.android.settingslib.Utils
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged
+import com.android.systemui.statusbar.policy.onThemeChanged
+import com.android.systemui.util.kotlin.emitOnStart
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Configuration-aware-state-tracking utilities. */
+class ConfigurationState
+@Inject
+constructor(
+ private val configurationController: ConfigurationController,
+ @Application private val context: Context,
+) {
+ /**
+ * Returns a [Flow] that emits a dimension pixel size that is kept in sync with the device
+ * configuration.
+ *
+ * @see android.content.res.Resources.getDimensionPixelSize
+ */
+ fun getDimensionPixelSize(@DimenRes id: Int): Flow<Int> {
+ return configurationController.onDensityOrFontScaleChanged.emitOnStart().map {
+ context.resources.getDimensionPixelSize(id)
+ }
+ }
+
+ /**
+ * Returns a [Flow] that emits a color that is kept in sync with the device theme.
+ *
+ * @see Utils.getColorAttrDefaultColor
+ */
+ fun getColorAttr(@AttrRes id: Int, @ColorInt defaultValue: Int): Flow<Int> {
+ return configurationController.onThemeChanged.emitOnStart().map {
+ Utils.getColorAttrDefaultColor(context, id, defaultValue)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/CommonUiDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/CommonUiDataLayerModule.kt
new file mode 100644
index 0000000..b0e6931
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/CommonUiDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.common.ui.data
+
+import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryModule
+import dagger.Module
+
+@Module(includes = [ConfigurationRepositoryModule::class]) object CommonUiDataLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index b8de8d8..e449274 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -13,18 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.common.ui.data.repository
import android.content.Context
import android.content.res.Configuration
import android.view.DisplayInfo
+import androidx.annotation.DimenRes
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.wrapper.DisplayUtilsWrapper
+import dagger.Binds
+import dagger.Module
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -48,7 +52,6 @@
fun getDimensionPixelSize(id: Int): Int
}
-@ExperimentalCoroutinesApi
@SysUISingleton
class ConfigurationRepositoryImpl
@Inject
@@ -119,7 +122,12 @@
return 1f
}
- override fun getDimensionPixelSize(id: Int): Int {
+ override fun getDimensionPixelSize(@DimenRes id: Int): Int {
return context.resources.getDimensionPixelSize(id)
}
}
+
+@Module
+interface ConfigurationRepositoryModule {
+ @Binds fun bindImpl(impl: ConfigurationRepositoryImpl): ConfigurationRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f0d7592..04b2852d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -41,7 +41,7 @@
import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
-import com.android.systemui.common.ui.data.repository.CommonRepositoryModule;
+import com.android.systemui.common.ui.data.CommonUiDataLayerModule;
import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.controls.dagger.ControlsModule;
@@ -170,7 +170,7 @@
BouncerViewModule.class,
ClipboardOverlayModule.class,
ClockRegistryModule.class,
- CommonRepositoryModule.class,
+ CommonUiDataLayerModule.class,
CommunalModule.class,
ConnectivityModule.class,
ControlsModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index e2de37f..22912df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -17,18 +17,13 @@
package com.android.systemui.statusbar.dagger
import com.android.systemui.CoreStartable
-import com.android.systemui.statusbar.core.StatusBarInitializer
-import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepository
-import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryImpl
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryImpl
+import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.phone.LightBarController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
-import dagger.multibindings.IntoSet
/**
* A module for **only** classes related to the status bar **UI element**. This module specifically
@@ -38,24 +33,9 @@
* ([com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule],
* [com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule], etc.).
*/
-@Module
+@Module(includes = [StatusBarDataLayerModule::class])
abstract class StatusBarModule {
@Binds
- abstract fun bindStatusBarModeRepository(
- impl: StatusBarModeRepositoryImpl
- ): StatusBarModeRepository
-
- @Binds
- @IntoMap
- @ClassKey(StatusBarModeRepositoryImpl::class)
- abstract fun bindStatusBarModeRepositoryStart(impl: StatusBarModeRepositoryImpl): CoreStartable
-
- @Binds
- abstract fun bindKeyguardStatusBarRepository(
- impl: KeyguardStatusBarRepositoryImpl
- ): KeyguardStatusBarRepository
-
- @Binds
@IntoMap
@ClassKey(OngoingCallController::class)
abstract fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
@@ -64,10 +44,4 @@
@IntoMap
@ClassKey(LightBarController::class)
abstract fun bindLightBarController(impl: LightBarController): CoreStartable
-
- @Binds
- @IntoSet
- abstract fun statusBarInitializedListener(
- statusBarModeRepository: StatusBarModeRepository,
- ): StatusBarInitializer.OnStatusBarViewInitializedListener
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
new file mode 100644
index 0000000..29d53fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.statusbar.data
+
+import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule
+import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ KeyguardStatusBarRepositoryModule::class,
+ StatusBarModeRepositoryModule::class,
+ StatusBarPhoneDataLayerModule::class
+ ]
+)
+object StatusBarDataLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
index 8136de9..d1594ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
@@ -22,6 +22,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.user.data.repository.UserSwitcherRepository
+import dagger.Binds
+import dagger.Module
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -78,3 +80,8 @@
isEnabled && isKeyguardEnabled
}
}
+
+@Module
+interface KeyguardStatusBarRepositoryModule {
+ @Binds fun bindImpl(impl: KeyguardStatusBarRepositoryImpl): KeyguardStatusBarRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
index 2b05994..47994d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
@@ -30,7 +30,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.DisplayId
import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.statusbar.core.StatusBarInitializer
+import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
import com.android.systemui.statusbar.data.model.StatusBarAppearance
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.phone.BoundsPair
@@ -38,6 +38,11 @@
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import dagger.multibindings.IntoSet
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -56,7 +61,7 @@
* Note: These status bar modes are status bar *window* states that are sent to us from
* WindowManager, not determined internally.
*/
-interface StatusBarModeRepository : StatusBarInitializer.OnStatusBarViewInitializedListener {
+interface StatusBarModeRepository {
/**
* True if the status bar window is showing transiently and will disappear soon, and false
* otherwise. ("Otherwise" in this case means the status bar is persistently hidden OR
@@ -112,7 +117,7 @@
private val commandQueue: CommandQueue,
private val letterboxAppearanceCalculator: LetterboxAppearanceCalculator,
ongoingCallRepository: OngoingCallRepository,
-) : StatusBarModeRepository, CoreStartable {
+) : StatusBarModeRepository, CoreStartable, OnStatusBarViewInitializedListener {
private val commandQueueCallback =
object : CommandQueue.Callbacks {
@@ -334,3 +339,17 @@
val statusBarBounds: BoundsPair,
)
}
+
+@Module
+interface StatusBarModeRepositoryModule {
+ @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepository
+
+ @Binds
+ @IntoMap
+ @ClassKey(StatusBarModeRepositoryImpl::class)
+ fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
+
+ @Binds
+ @IntoSet
+ fun bindViewInitListener(impl: StatusBarModeRepositoryImpl): OnStatusBarViewInitializedListener
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 62a0d13..c2a021d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -16,25 +16,32 @@
package com.android.systemui.statusbar.notification.collection.coordinator
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.collection.render.NotifStats
+import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
- * A small coordinator which updates the notif stack (the view layer which holds notifications)
- * with high-level data after the stack is populated with the final entries.
+ * A small coordinator which updates the notif stack (the view layer which holds notifications) with
+ * high-level data after the stack is populated with the final entries.
*/
@CoordinatorScope
-class StackCoordinator @Inject internal constructor(
+class StackCoordinator
+@Inject
+internal constructor(
+ private val featureFlags: FeatureFlagsClassic,
private val groupExpansionManagerImpl: GroupExpansionManagerImpl,
- private val notificationIconAreaController: NotificationIconAreaController
+ private val notificationIconAreaController: NotificationIconAreaController,
+ private val renderListInteractor: RenderNotificationListInteractor,
) : Coordinator {
override fun attach(pipeline: NotifPipeline) {
@@ -46,6 +53,9 @@
traceSection("StackCoordinator.onAfterRenderList") {
controller.setNotifStats(calculateNotifStats(entries))
notificationIconAreaController.updateNotificationIcons(entries)
+ if (featureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+ renderListInteractor.setRenderedList(entries)
+ }
}
private fun calculateNotifStats(entries: List<ListEntry>): NotifStats {
@@ -75,4 +85,4 @@
hasClearableSilentNotifs = hasClearableSilentNotifs
)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index 5435fb5..4126c5ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -15,8 +15,15 @@
*/
package com.android.systemui.statusbar.notification.data
+import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardStateRepositoryModule
import dagger.Module
-@Module(includes = [NotificationsKeyguardStateRepositoryModule::class])
+@Module(
+ includes =
+ [
+ NotificationStackRepositoryModule::class,
+ NotificationsKeyguardStateRepositoryModule::class,
+ ]
+)
interface NotificationDataLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt
new file mode 100644
index 0000000..c371f4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationStackRepository.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/**
+ * Repository of notifications in the notification stack.
+ *
+ * This repository serves as the boundary between the
+ * [com.android.systemui.statusbar.notification.collection.NotifPipeline] and the modern
+ * notifications presentation codebase.
+ */
+interface NotificationStackRepository {
+ /**
+ * Notifications actively presented to the user in the notification stack.
+ *
+ * @see com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
+ */
+ val renderedEntries: Flow<List<ListEntry>>
+}
+
+/**
+ * A mutable implementation of [NotificationStackRepository]. Like other "mutable" objects, the
+ * mutable type should only be exposed where necessary; most consumers should only have access to it
+ * from behind the immutable [NotificationStackRepository] interface.
+ */
+@SysUISingleton
+class MutableNotificationStackRepository @Inject constructor() : NotificationStackRepository {
+ override val renderedEntries = MutableStateFlow(emptyList<ListEntry>())
+}
+
+@Module
+interface NotificationStackRepositoryModule {
+ @Binds fun bindImpl(impl: MutableNotificationStackRepository): NotificationStackRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt
index 8f7e269..02a667f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt
@@ -18,7 +18,10 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepository
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
/** Interactor for notifications in general. */
@SysUISingleton
@@ -26,9 +29,12 @@
@Inject
constructor(
private val disableFlagsRepository: DisableFlagsRepository,
+ stackRepository: NotificationStackRepository,
) {
/** Returns true if notification alerts are allowed. */
- fun areNotificationAlertsEnabled(): Boolean {
- return disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled()
- }
+ fun areNotificationAlertsEnabled(): Boolean =
+ disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled()
+
+ /** Notifications actively presented to the user in the notification stack. */
+ val notifications: Flow<List<ListEntry>> = stackRepository.renderedEntries
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
new file mode 100644
index 0000000..ea9b4e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 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.statusbar.notification.domain.interactor
+
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.data.repository.MutableNotificationStackRepository
+import javax.inject.Inject
+
+/**
+ * Logic for passing information from the
+ * [com.android.systemui.statusbar.notification.collection.NotifPipeline] to the presentation
+ * layers.
+ */
+class RenderNotificationListInteractor
+@Inject
+constructor(
+ private val repository: MutableNotificationStackRepository,
+) {
+ /**
+ * Sets the current list of rendered notification entries as displayed in the notification
+ * stack.
+ *
+ * @see com.android.systemui.statusbar.notification.data.repository.NotificationStackRepository.renderedEntries
+ */
+ fun setRenderedList(entries: List<ListEntry>) {
+ repository.renderedEntries.value = entries.toList()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
index eb5c1fa..de011db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -16,32 +16,27 @@
package com.android.systemui.statusbar.notification.icon.ui.viewbinder
import android.content.Context
-import android.graphics.Color
import android.graphics.Rect
import android.os.Bundle
import android.os.Trace
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
-import androidx.annotation.ColorInt
import androidx.annotation.VisibleForTesting
import androidx.collection.ArrayMap
import com.android.internal.statusbar.StatusBarIcon
-import com.android.internal.util.ContrastColorUtil
-import com.android.settingslib.Utils
+import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.flags.RefactorFlag
-import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.notification.NotificationUtils
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -55,7 +50,6 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional
@@ -75,44 +69,34 @@
@Inject
constructor(
private val context: Context,
+ private val configuration: ConfigurationState,
private val wakeUpCoordinator: NotificationWakeUpCoordinator,
private val bypassController: KeyguardBypassController,
- private val configurationController: ConfigurationController,
private val mediaManager: NotificationMediaManager,
notificationListener: NotificationListener,
private val dozeParameters: DozeParameters,
private val sectionStyleProvider: SectionStyleProvider,
private val bubblesOptional: Optional<Bubbles>,
demoModeController: DemoModeController,
- darkIconDispatcher: DarkIconDispatcher,
private val featureFlags: FeatureFlagsClassic,
private val statusBarWindowController: StatusBarWindowController,
private val screenOffAnimationController: ScreenOffAnimationController,
private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
private val statusBarIconsViewModel: NotificationIconContainerStatusBarViewModel,
private val aodIconsViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
-) :
- NotificationIconAreaController,
- DarkIconDispatcher.DarkReceiver,
- NotificationWakeUpCoordinator.WakeUpListener,
- DemoMode {
+) : NotificationIconAreaController, NotificationWakeUpCoordinator.WakeUpListener, DemoMode {
- private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context)
private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }
private val shelfRefactor = RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
- private val tintAreas = ArrayList<Rect>()
private var iconSize = 0
private var iconHPadding = 0
- private var iconTint = Color.WHITE
private var notificationEntries = listOf<ListEntry>()
private var notificationIconArea: View? = null
private var notificationIcons: NotificationIconContainer? = null
private var shelfIcons: NotificationIconContainer? = null
private var aodIcons: NotificationIconContainer? = null
private var aodBindJob: DisposableHandle? = null
- private var aodIconAppearTranslation = 0
- private var aodIconTint = 0
private var showLowPriority = true
@VisibleForTesting
@@ -129,8 +113,6 @@
demoModeController.addCallback(this)
notificationListener.addNotificationSettingsListener(settingsListener)
initializeNotificationAreaViews(context)
- reloadAodColor()
- darkIconDispatcher.addDarkReceiver(this)
}
@VisibleForTesting
@@ -152,7 +134,7 @@
NotificationIconContainerViewBinder.bind(
aodIcons,
aodIconsViewModel,
- configurationController,
+ configuration,
dozeParameters,
featureFlags,
screenOffAnimationController,
@@ -167,16 +149,17 @@
NotificationShelfViewBinderWrapperControllerImpl.unsupported
override fun setShelfIcons(icons: NotificationIconContainer) {
- if (shelfRefactor.isUnexpectedlyInLegacyMode()) return
- NotificationIconContainerViewBinder.bind(
- icons,
- shelfIconsViewModel,
- configurationController,
- dozeParameters,
- featureFlags,
- screenOffAnimationController,
- )
- shelfIcons = icons
+ if (shelfRefactor.isUnexpectedlyInLegacyMode()) {
+ NotificationIconContainerViewBinder.bind(
+ icons,
+ shelfIconsViewModel,
+ configuration,
+ dozeParameters,
+ featureFlags,
+ screenOffAnimationController,
+ )
+ shelfIcons = icons
+ }
}
override fun onDensityOrFontScaleChanged(context: Context) {
@@ -188,22 +171,6 @@
return notificationIconArea
}
- /**
- * See [com.android.systemui.statusbar.policy.DarkIconDispatcher.setIconsDarkArea]. Sets the
- * color that should be used to tint any icons in the notification area.
- *
- * @param tintAreas the areas in which to tint the icons, specified in screen coordinates
- * @param darkIntensity
- */
- override fun onDarkChanged(tintAreas: ArrayList<Rect>, darkIntensity: Float, iconTint: Int) {
- this.tintAreas.clear()
- this.tintAreas.addAll(tintAreas)
- if (DarkIconDispatcher.isInAreas(tintAreas, notificationIconArea)) {
- this.iconTint = iconTint
- }
- applyNotificationIconsTint()
- }
-
/** Updates the notifications with the given list of notifications to display. */
override fun updateNotificationIcons(entries: List<ListEntry>) {
notificationEntries = entries
@@ -249,10 +216,7 @@
override fun setAnimationsEnabled(enabled: Boolean) = unsupported
- override fun onThemeChanged() {
- reloadAodColor()
- updateAodIconColors()
- }
+ override fun onThemeChanged() = unsupported
override fun getHeight(): Int {
return if (aodIcons == null) 0 else aodIcons!!.height
@@ -260,7 +224,6 @@
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
updateAodNotificationIcons()
- updateAodIconColors()
}
override fun demoCommands(): List<String> {
@@ -296,7 +259,7 @@
NotificationIconContainerViewBinder.bind(
notificationIcons!!,
statusBarIconsViewModel,
- configurationController,
+ configuration,
dozeParameters,
featureFlags,
screenOffAnimationController,
@@ -335,7 +298,6 @@
val res = context.resources
iconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp)
iconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin)
- aodIconAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation)
}
private fun shouldShowNotificationIcon(
@@ -383,7 +345,6 @@
updateStatusBarIcons()
updateShelfIcons()
updateAodNotificationIcons()
- applyNotificationIconsTint()
Trace.endSection()
}
@@ -526,55 +487,7 @@
hostLayout.setReplacingIcons(null)
}
- /** Applies [.mIconTint] to the notification icons. */
- private fun applyNotificationIconsTint() {
- for (i in 0 until notificationIcons!!.childCount) {
- val iv = notificationIcons!!.getChildAt(i) as StatusBarIconView
- if (iv.width != 0) {
- updateTintForIcon(iv, iconTint)
- } else {
- iv.executeOnLayout { updateTintForIcon(iv, iconTint) }
- }
- }
- updateAodIconColors()
- }
-
- private fun updateTintForIcon(v: StatusBarIconView, tint: Int) {
- val isPreL = java.lang.Boolean.TRUE == v.getTag(R.id.icon_is_pre_L)
- var color = StatusBarIconView.NO_COLOR
- val colorize = !isPreL || NotificationUtils.isGrayscale(v, contrastColorUtil)
- if (colorize) {
- color = DarkIconDispatcher.getTint(tintAreas, v, tint)
- }
- v.staticDrawableColor = color
- v.setDecorColor(tint)
- }
-
- private fun reloadAodColor() {
- aodIconTint =
- Utils.getColorAttrDefaultColor(
- context,
- R.attr.wallpaperTextColor,
- DEFAULT_AOD_ICON_COLOR
- )
- }
-
- private fun updateAodIconColors() {
- if (aodIcons != null) {
- for (i in 0 until aodIcons!!.childCount) {
- val iv = aodIcons!!.getChildAt(i) as StatusBarIconView
- if (iv.width != 0) {
- updateTintForIcon(iv, aodIconTint)
- } else {
- iv.executeOnLayout { updateTintForIcon(iv, aodIconTint) }
- }
- }
- }
- }
-
companion object {
- @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1
-
val unsupported: Nothing
get() =
error(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 0d2f00a..079004c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -15,27 +15,30 @@
*/
package com.android.systemui.statusbar.notification.icon.ui.viewbinder
-import android.content.res.Resources
+import android.graphics.Rect
import android.view.View
-import androidx.annotation.DimenRes
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
+import com.android.internal.util.ContrastColorUtil
+import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.statusbar.CrossFadeHelper
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.NotificationUtils
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged
-import com.android.systemui.util.kotlin.stateFlow
-import kotlinx.coroutines.CoroutineScope
+import com.android.systemui.util.children
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
@@ -43,11 +46,12 @@
fun bind(
view: NotificationIconContainer,
viewModel: NotificationIconContainerViewModel,
- configurationController: ConfigurationController,
+ configuration: ConfigurationState,
dozeParameters: DozeParameters,
featureFlags: FeatureFlagsClassic,
screenOffAnimationController: ScreenOffAnimationController,
): DisposableHandle {
+ val contrastColorUtil = ContrastColorUtil.getInstance(view.context)
return view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) }
@@ -59,15 +63,13 @@
}
}
}
- // TODO(278765923): this should live where AOD is bound, not inside of the NIC
+ // TODO(b/278765923): this should live where AOD is bound, not inside of the NIC
// view-binder
launch {
val iconAppearTranslation =
- view.resources.getConfigAwareDimensionPixelSize(
- this,
- configurationController,
- R.dimen.shelf_appear_translation,
- )
+ configuration
+ .getDimensionPixelSize(R.dimen.shelf_appear_translation)
+ .stateIn(this)
bindVisibility(
viewModel,
view,
@@ -78,9 +80,40 @@
viewModel.completeVisibilityAnimation()
}
}
+ launch {
+ viewModel.iconColors
+ .mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
+ .collect { iconLookup -> applyTint(view, iconLookup, contrastColorUtil) }
+ }
}
}
}
+
+ // TODO(b/305739416): Once SBIV has its own Recommended Architecture stack, this can be moved
+ // there and cleaned up.
+ private fun applyTint(
+ view: NotificationIconContainer,
+ iconColors: IconColors,
+ contrastColorUtil: ContrastColorUtil,
+ ) {
+ view.children.filterIsInstance<StatusBarIconView>().forEach { iv ->
+ if (iv.width != 0) {
+ updateTintForIcon(iv, iconColors, contrastColorUtil)
+ }
+ }
+ }
+
+ private fun updateTintForIcon(
+ v: StatusBarIconView,
+ iconColors: IconColors,
+ contrastColorUtil: ContrastColorUtil,
+ ) {
+ val isPreL = java.lang.Boolean.TRUE == v.getTag(R.id.icon_is_pre_L)
+ val isColorized = !isPreL || NotificationUtils.isGrayscale(v, contrastColorUtil)
+ v.staticDrawableColor = iconColors.staticDrawableColor(v.viewBounds, isColorized)
+ v.setDecorColor(iconColors.tint)
+ }
+
private suspend fun bindVisibility(
viewModel: NotificationIconContainerViewModel,
view: NotificationIconContainer,
@@ -173,14 +206,16 @@
}
private const val AOD_ICONS_APPEAR_DURATION: Long = 200
-}
-fun Resources.getConfigAwareDimensionPixelSize(
- scope: CoroutineScope,
- configurationController: ConfigurationController,
- @DimenRes id: Int,
-): StateFlow<Int> =
- scope.stateFlow(
- changedSignals = configurationController.onDensityOrFontScaleChanged,
- getValue = { getDimensionPixelSize(id) }
- )
+ private val View.viewBounds: Rect
+ get() {
+ val tmpArray = intArrayOf(0, 0)
+ getLocationOnScreen(tmpArray)
+ return Rect(
+ /* left = */ tmpArray[0],
+ /* top = */ tmpArray[1],
+ /* right = */ left + width,
+ /* bottom = */ top + height,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
index 3289a3c..e9de4bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -15,6 +15,10 @@
*/
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+import android.graphics.Color
+import android.graphics.Rect
+import androidx.annotation.ColorInt
+import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.flags.FeatureFlagsClassic
@@ -23,8 +27,11 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.kotlin.pairwise
@@ -44,6 +51,7 @@
class NotificationIconContainerAlwaysOnDisplayViewModel
@Inject
constructor(
+ configuration: ConfigurationState,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val dozeParameters: DozeParameters,
private val featureFlags: FeatureFlagsClassic,
@@ -57,6 +65,11 @@
private val onDozeAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
private val onVisAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+ override val iconColors: Flow<ColorLookup> =
+ configuration.getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR).map { tint ->
+ ColorLookup { IconColorsImpl(tint) }
+ }
+
override val animationsEnabled: Flow<Boolean> =
combine(
shadeInteractor.isShadeTouchable,
@@ -157,4 +170,12 @@
}
.toAnimatedValueFlow(completionEvents = onVisAnimationComplete)
}
+
+ private class IconColorsImpl(override val tint: Int) : IconColors {
+ override fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int = tint
+ }
+
+ companion object {
+ @ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
index c44a2b6..f305155 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
import com.android.systemui.util.ui.AnimatedValue
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -29,4 +30,5 @@
override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
override fun completeDozeAnimation() {}
override fun completeVisibilityAnimation() {}
+ override val iconColors: Flow<ColorLookup> = emptyFlow()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index 035687a..40cc294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -15,8 +15,14 @@
*/
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+import android.graphics.Rect
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
+import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor
import com.android.systemui.util.ui.AnimatedValue
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -27,7 +33,9 @@
class NotificationIconContainerStatusBarViewModel
@Inject
constructor(
+ darkIconInteractor: DarkIconInteractor,
keyguardInteractor: KeyguardInteractor,
+ notificationsInteractor: NotificationsInteractor,
shadeInteractor: ShadeInteractor,
) : NotificationIconContainerViewModel {
override val animationsEnabled: Flow<Boolean> =
@@ -37,9 +45,36 @@
) { panelTouchesEnabled, isKeyguardShowing ->
panelTouchesEnabled && !isKeyguardShowing
}
-
+ override val iconColors: Flow<ColorLookup> =
+ combine(
+ darkIconInteractor.tintAreas,
+ darkIconInteractor.tintColor,
+ // Included so that tints are re-applied after entries are changed.
+ notificationsInteractor.notifications,
+ ) { areas, tint, _ ->
+ ColorLookup { viewBounds: Rect ->
+ if (DarkIconDispatcher.isInAreas(areas, viewBounds)) {
+ IconColorsImpl(tint, areas)
+ } else {
+ null
+ }
+ }
+ }
override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow()
override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
override fun completeDozeAnimation() {}
override fun completeVisibilityAnimation() {}
+
+ private class IconColorsImpl(
+ override val tint: Int,
+ private val areas: Collection<Rect>,
+ ) : IconColors {
+ override fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int {
+ return if (isColorized && DarkIconDispatcher.isInAreas(areas, viewBounds)) {
+ tint
+ } else {
+ DarkIconDispatcher.DEFAULT_ICON_TINT
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
index 65eb220..c98811b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+import android.graphics.Rect
import com.android.systemui.util.ui.AnimatedValue
import kotlinx.coroutines.flow.Flow
@@ -23,6 +24,7 @@
* AOD.
*/
interface NotificationIconContainerViewModel {
+
/** Are changes to the icon container animated? */
val animationsEnabled: Flow<Boolean>
@@ -32,15 +34,39 @@
/** Is the icon container visible? */
val isVisible: Flow<AnimatedValue<Boolean>>
+ /** The colors with which to display the notification icons. */
+ val iconColors: Flow<ColorLookup>
+
/**
* Signal completion of the [isDozing] animation; if [isDozing]'s [AnimatedValue.isAnimating]
- * property was `true`, calling this method will update it to `false.
+ * property was `true`, calling this method will update it to `false`.
*/
fun completeDozeAnimation()
/**
* Signal completion of the [isVisible] animation; if [isVisible]'s [AnimatedValue.isAnimating]
- * property was `true`, calling this method will update it to `false.
+ * property was `true`, calling this method will update it to `false`.
*/
fun completeVisibilityAnimation()
+
+ /**
+ * Lookup the colors to use for the notification icons based on the bounds of the icon
+ * container. A result of `null` indicates that no color changes should be applied.
+ */
+ fun interface ColorLookup {
+ fun iconColors(viewBounds: Rect): IconColors?
+ }
+
+ /** Colors to apply to notification icons. */
+ interface IconColors {
+
+ /** A tint to apply to the icons. */
+ val tint: Int
+
+ /**
+ * Returns the color to be applied to an icon, based on that icon's view bounds and whether
+ * or not the notification icon is colorized.
+ */
+ fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7cd32f9..cb85966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3124,7 +3124,9 @@
if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
}
- mNotificationIconAreaController.onThemeChanged();
+ if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+ mNotificationIconAreaController.onThemeChanged();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/StatusBarPhoneDataLayerModule.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/data/StatusBarPhoneDataLayerModule.kt
index 9b0c3fa..9645c69 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/CommonRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/StatusBarPhoneDataLayerModule.kt
@@ -13,13 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.statusbar.phone.data
-package com.android.systemui.common.ui.data.repository
-
-import dagger.Binds
+import com.android.systemui.statusbar.phone.data.repository.DarkIconRepositoryModule
import dagger.Module
-@Module
-interface CommonRepositoryModule {
- @Binds fun bindRepository(impl: ConfigurationRepositoryImpl): ConfigurationRepository
-}
+@Module(includes = [DarkIconRepositoryModule::class]) object StatusBarPhoneDataLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
new file mode 100644
index 0000000..ba377497
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.statusbar.phone.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+/** Dark-mode state for tinting icons. */
+interface DarkIconRepository {
+ val darkState: StateFlow<DarkChange>
+}
+
+@SysUISingleton
+class DarkIconRepositoryImpl
+@Inject
+constructor(
+ darkIconDispatcher: SysuiDarkIconDispatcher,
+) : DarkIconRepository {
+ override val darkState: StateFlow<DarkChange> = darkIconDispatcher.darkChangeFlow()
+}
+
+@Module
+interface DarkIconRepositoryModule {
+ @Binds fun bindImpl(impl: DarkIconRepositoryImpl): DarkIconRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractor.kt
new file mode 100644
index 0000000..246645e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.statusbar.phone.domain.interactor
+
+import android.graphics.Rect
+import com.android.systemui.statusbar.phone.data.repository.DarkIconRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** States pertaining to calculating colors for icons in dark mode. */
+class DarkIconInteractor @Inject constructor(repository: DarkIconRepository) {
+ /** @see com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange.areas */
+ val tintAreas: Flow<Collection<Rect>> = repository.darkState.map { it.areas }
+ /**
+ * @see com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange.darkIntensity
+ */
+ val darkIntensity: Flow<Float> = repository.darkState.map { it.darkIntensity }
+ /** @see com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange.tint */
+ val tintColor: Flow<Int> = repository.darkState.map { it.tint }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
index 21acfb4..25d67af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
@@ -13,7 +13,7 @@
*/
package com.android.systemui.statusbar.policy
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -23,14 +23,30 @@
* @see ConfigurationController.ConfigurationListener.onDensityOrFontScaleChanged
*/
val ConfigurationController.onDensityOrFontScaleChanged: Flow<Unit>
- get() =
- ConflatedCallbackFlow.conflatedCallbackFlow {
- val listener =
- object : ConfigurationController.ConfigurationListener {
- override fun onDensityOrFontScaleChanged() {
- trySend(Unit)
- }
+ get() = conflatedCallbackFlow {
+ val listener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onDensityOrFontScaleChanged() {
+ trySend(Unit)
}
- addCallback(listener)
- awaitClose { removeCallback(listener) }
- }
+ }
+ addCallback(listener)
+ awaitClose { removeCallback(listener) }
+ }
+
+/**
+ * A [Flow] that emits whenever the theme has changed.
+ *
+ * @see ConfigurationController.ConfigurationListener.onThemeChanged
+ */
+val ConfigurationController.onThemeChanged: Flow<Unit>
+ get() = conflatedCallbackFlow {
+ val listener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onThemeChanged() {
+ trySend(Unit)
+ }
+ }
+ addCallback(listener)
+ awaitClose { removeCallback(listener) }
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index b3834f5..31b90ba 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -373,4 +373,11 @@
args[6] as T9,
)
}
-}
\ No newline at end of file
+}
+
+/**
+ * Returns a [Flow] that immediately emits [Unit] when started, then emits from the given upstream
+ * [Flow] as normal.
+ */
+@Suppress("NOTHING_TO_INLINE")
+inline fun Flow<Unit>.emitOnStart(): Flow<Unit> = onStart { emit(Unit) }
diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
index 0b3c3b4..ed0541a 100644
--- a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
+++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
@@ -17,11 +17,17 @@
import android.content.Context
import android.content.res.Resources
+import android.testing.TestableContext
+import android.testing.TestableResources
import com.android.systemui.FakeSystemUiModule
import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.FakeBroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule
+import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -33,15 +39,29 @@
FakeSystemUiModule::class,
]
)
-class SysUITestModule {
- @Provides fun provideContext(test: SysuiTestCase): Context = test.context
+interface SysUITestModule {
- @Provides @Application fun provideAppContext(test: SysuiTestCase): Context = test.context
+ @Binds fun bindTestableContext(sysuiTestableContext: SysuiTestableContext): TestableContext
+ @Binds fun bindContext(testableContext: TestableContext): Context
+ @Binds @Application fun bindAppContext(context: Context): Context
+ @Binds @Application fun bindAppResources(resources: Resources): Resources
+ @Binds @Main fun bindMainResources(resources: Resources): Resources
+ @Binds fun bindBroadcastDispatcher(fake: FakeBroadcastDispatcher): BroadcastDispatcher
- @Provides @Main
- fun provideResources(@Application context: Context): Resources = context.resources
+ companion object {
+ @Provides
+ fun provideSysuiTestableContext(test: SysuiTestCase): SysuiTestableContext = test.context
- @Provides
- fun provideBroadcastDispatcher(test: SysuiTestCase): BroadcastDispatcher =
- test.fakeBroadcastDispatcher
+ @Provides
+ fun provideTestableResources(context: TestableContext): TestableResources =
+ context.getOrCreateTestableResources()
+
+ @Provides
+ fun provideResources(testableResources: TestableResources): Resources =
+ testableResources.resources
+
+ @Provides
+ fun provideFakeBroadcastDispatcher(test: SysuiTestCase): FakeBroadcastDispatcher =
+ test.fakeBroadcastDispatcher
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index 655bd72..a736182 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -19,6 +19,8 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -27,6 +29,7 @@
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.collection.render.NotifStats
+import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationIconAreaController
@@ -37,8 +40,8 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations.initMocks
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations.initMocks
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -52,13 +55,23 @@
@Mock private lateinit var pipeline: NotifPipeline
@Mock private lateinit var groupExpansionManagerImpl: GroupExpansionManagerImpl
@Mock private lateinit var notificationIconAreaController: NotificationIconAreaController
+ @Mock private lateinit var renderListInteractor: RenderNotificationListInteractor
@Mock private lateinit var stackController: NotifStackController
@Mock private lateinit var section: NotifSection
+ val featureFlags =
+ FakeFeatureFlagsClassic().apply { setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR) }
+
@Before
fun setUp() {
initMocks(this)
- coordinator = StackCoordinator(groupExpansionManagerImpl, notificationIconAreaController)
+ coordinator =
+ StackCoordinator(
+ featureFlags,
+ groupExpansionManagerImpl,
+ notificationIconAreaController,
+ renderListInteractor,
+ )
coordinator.attach(pipeline)
afterRenderListListener = withArgCaptor {
verify(pipeline).addOnAfterRenderListListener(capture())
@@ -68,11 +81,19 @@
@Test
fun testUpdateNotificationIcons() {
+ featureFlags.set(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR, false)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(notificationIconAreaController).updateNotificationIcons(eq(listOf(entry)))
}
@Test
+ fun testSetRenderedListOnInteractor() {
+ featureFlags.set(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR, true)
+ afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
+ verify(renderListInteractor).setRenderedList(eq(listOf(entry)))
+ }
+
+ @Test
fun testSetNotificationStats_clearableAlerting() {
whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt
index fe49016..6bf9e35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt
@@ -16,84 +16,53 @@
import android.app.StatusBarManager
import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepositoryImpl
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import org.junit.Before
+import dagger.BindsInstance
+import dagger.Component
import org.junit.Test
-import org.mockito.Mockito.verify
@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
class NotificationsInteractorTest : SysuiTestCase() {
- private lateinit var underTest: NotificationsInteractor
+ @Component(modules = [SysUITestModule::class])
+ @SysUISingleton
+ interface TestComponent {
+ val underTest: NotificationsInteractor
+ val disableFlags: FakeDisableFlagsRepository
- private val testScope = TestScope(UnconfinedTestDispatcher())
- private val commandQueue: CommandQueue = mock()
- private val logBuffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
- private val disableFlagsLogger = DisableFlagsLogger()
- private lateinit var disableFlagsRepository: DisableFlagsRepository
-
- @Before
- fun setUp() {
- disableFlagsRepository =
- DisableFlagsRepositoryImpl(
- commandQueue,
- DISPLAY_ID,
- testScope.backgroundScope,
- mock(),
- logBuffer,
- disableFlagsLogger,
- )
- underTest = NotificationsInteractor(disableFlagsRepository)
+ @Component.Factory
+ interface Factory {
+ fun create(@BindsInstance test: SysuiTestCase): TestComponent
+ }
}
+ private val testComponent: TestComponent =
+ DaggerNotificationsInteractorTest_TestComponent.factory().create(test = this)
+
@Test
- fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() {
- val callback = getCommandQueueCallback()
-
- callback.disable(
- DISPLAY_ID,
- StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NONE,
- /* animate= */ false
- )
-
- assertThat(underTest.areNotificationAlertsEnabled()).isTrue()
- }
+ fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() =
+ with(testComponent) {
+ disableFlags.disableFlags.value =
+ DisableFlagsModel(
+ StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NONE,
+ )
+ assertThat(underTest.areNotificationAlertsEnabled()).isTrue()
+ }
@Test
- fun disableFlags_notifAlertsDisabled_notifAlertsEnabledFalse() {
- val callback = getCommandQueueCallback()
-
- callback.disable(
- DISPLAY_ID,
- StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
- StatusBarManager.DISABLE2_NONE,
- /* animate= */ false
- )
-
- assertThat(underTest.areNotificationAlertsEnabled()).isFalse()
- }
-
- private fun getCommandQueueCallback(): CommandQueue.Callbacks {
- val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
- verify(commandQueue).addCallback(callbackCaptor.capture())
- return callbackCaptor.value
- }
-
- private companion object {
- const val DISPLAY_ID = 1
- }
+ fun disableFlags_notifAlertsDisabled_notifAlertsEnabledFalse() =
+ with(testComponent) {
+ disableFlags.disableFlags.value =
+ DisableFlagsModel(
+ StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
+ StatusBarManager.DISABLE2_NONE,
+ )
+ assertThat(underTest.areNotificationAlertsEnabled()).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index e1e7f92..e21ebeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.SysUITestModule
@@ -34,10 +35,13 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
+import com.android.systemui.statusbar.phone.data.repository.FakeDarkIconRepository
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
import com.android.systemui.user.domain.UserDomainLayerModule
import com.android.systemui.util.mockito.whenever
@@ -61,18 +65,6 @@
@Mock lateinit var dozeParams: DozeParameters
private lateinit var testComponent: TestComponent
- private val underTest: NotificationIconContainerStatusBarViewModel
- get() = testComponent.underTest
- private val deviceProvisioningRepository
- get() = testComponent.deviceProvisioningRepository
- private val keyguardTransitionRepository
- get() = testComponent.keyguardTransitionRepository
- private val keyguardRepository
- get() = testComponent.keyguardRepository
- private val powerRepository
- get() = testComponent.powerRepository
- private val scope
- get() = testComponent.scope
@Before
fun setup() {
@@ -82,7 +74,6 @@
DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
.create(
test = this,
- // Configurable bindings
featureFlags =
FakeFeatureFlagsClassicModule {
set(Flags.FACE_AUTH_REFACTOR, value = false)
@@ -93,155 +84,247 @@
dozeParameters = dozeParams,
),
)
-
- keyguardRepository.setKeyguardShowing(false)
- deviceProvisioningRepository.setFactoryResetProtectionActive(false)
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.OTHER,
- lastSleepReason = WakeSleepReason.OTHER,
- )
+ .apply {
+ keyguardRepository.setKeyguardShowing(false)
+ deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ }
}
@Test
fun animationsEnabled_isFalse_whenFrpIsActive() =
- scope.runTest {
- deviceProvisioningRepository.setFactoryResetProtectionActive(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
)
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
}
@Test
fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.ASLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
)
- )
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(
- to = DozeStateModel.DOZE_AOD,
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
)
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(
+ to = DozeStateModel.DOZE_AOD,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
}
@Test
fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.ASLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
)
- )
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(
- to = DozeStateModel.DOZE_PULSING,
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
)
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(
+ to = DozeStateModel.DOZE_PULSING,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
}
@Test
fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.STARTING_TO_SLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
)
- )
- whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
}
@Test
fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.STARTING_TO_SLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
)
- )
- whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
}
@Test
fun animationsEnabled_isTrue_whenNotAsleep() =
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
+ with(testComponent) {
+ scope.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
)
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
}
@Test
fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
- scope.runTest {
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ with(testComponent) {
+ scope.runTest {
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
)
- )
- keyguardRepository.setKeyguardShowing(true)
- runCurrent()
+ keyguardRepository.setKeyguardShowing(true)
+ runCurrent()
- assertThat(animationsEnabled).isFalse()
+ assertThat(animationsEnabled).isFalse()
- keyguardRepository.setKeyguardShowing(false)
- runCurrent()
+ keyguardRepository.setKeyguardShowing(false)
+ runCurrent()
- assertThat(animationsEnabled).isTrue()
+ assertThat(animationsEnabled).isTrue()
+ }
+ }
+
+ @Test
+ fun iconColors_testsDarkBounds() =
+ with(testComponent) {
+ scope.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ emptyList(),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ assertThat(iconColorsLookup).isNotNull()
+
+ val iconColors = iconColorsLookup?.iconColors(Rect())
+ assertThat(iconColors).isNotNull()
+ iconColors!!
+
+ assertThat(iconColors.tint).isEqualTo(0xAABBCC)
+
+ val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true)
+
+ assertThat(staticDrawableColor).isEqualTo(0xAABBCC)
+ }
+ }
+
+ @Test
+ fun iconColors_staticDrawableColor_nonColorized() =
+ with(testComponent) {
+ scope.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ emptyList(),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect())
+ val staticDrawableColor =
+ iconColors?.staticDrawableColor(Rect(), isColorized = false)
+ assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
+ }
+ }
+
+ @Test
+ fun iconColors_staticDrawableColor_isColorized_notInDarkTintArea() =
+ with(testComponent) {
+ scope.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ listOf(Rect(0, 0, 5, 5)),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4))
+ val staticDrawableColor =
+ iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true)
+ assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
+ }
+ }
+
+ @Test
+ fun iconColors_notInDarkTintArea() =
+ with(testComponent) {
+ scope.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ listOf(Rect(0, 0, 5, 5)),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7))
+ assertThat(iconColors).isNull()
+ }
}
@SysUISingleton
@@ -249,7 +332,6 @@
modules =
[
SysUITestModule::class,
- // Real impls
BiometricsDomainLayerModule::class,
UserDomainLayerModule::class,
]
@@ -258,6 +340,7 @@
val underTest: NotificationIconContainerStatusBarViewModel
+ val darkIconRepository: FakeDarkIconRepository
val deviceProvisioningRepository: FakeDeviceProvisioningRepository
val keyguardTransitionRepository: FakeKeyguardTransitionRepository
val keyguardRepository: FakeKeyguardRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
index aaf8d07..6e3a732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.util.ui
import android.testing.AndroidTestingRunner
@@ -20,6 +22,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.launchIn
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index 5dcc742..8353cf7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -34,7 +34,10 @@
private val _scaleForResolution = MutableStateFlow(1f)
override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
- suspend fun onAnyConfigurationChange() {
+ private val pixelSizes = mutableMapOf<Int, MutableStateFlow<Int>>()
+ private val colors = mutableMapOf<Int, MutableStateFlow<Int>>()
+
+ fun onAnyConfigurationChange() {
_onAnyConfigurationChange.tryEmit(Unit)
}
@@ -42,12 +45,12 @@
_scaleForResolution.value = scale
}
- override fun getResolutionScale(): Float {
- return _scaleForResolution.value
- }
+ override fun getResolutionScale(): Float = _scaleForResolution.value
- override fun getDimensionPixelSize(id: Int): Int {
- return 0
+ override fun getDimensionPixelSize(id: Int): Int = pixelSizes[id]?.value ?: 0
+
+ fun setDimensionPixelSize(id: Int, pixelSize: Int) {
+ pixelSizes.getOrPut(id) { MutableStateFlow(pixelSize) }.value = pixelSize
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
index e59f642..8f18e13 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
@@ -15,8 +15,10 @@
*/
package com.android.systemui.statusbar.data
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepositoryModule
import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule
import com.android.systemui.statusbar.notification.data.FakeStatusBarNotificationsDataLayerModule
+import com.android.systemui.statusbar.phone.data.FakeStatusBarPhoneDataLayerModule
import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule
import com.android.systemui.statusbar.policy.data.FakeStatusBarPolicyDataLayerModule
import dagger.Module
@@ -25,7 +27,9 @@
includes =
[
FakeStatusBarDisableFlagsDataLayerModule::class,
+ FakeStatusBarModeRepositoryModule::class,
FakeStatusBarNotificationsDataLayerModule::class,
+ FakeStatusBarPhoneDataLayerModule::class,
FakeStatusBarPipelineDataLayerModule::class,
FakeStatusBarPolicyDataLayerModule::class,
]
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
similarity index 81%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
index 61ba464..f25d282 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
@@ -18,17 +18,17 @@
import com.android.systemui.statusbar.data.model.StatusBarAppearance
import com.android.systemui.statusbar.data.model.StatusBarMode
-import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeStatusBarModeRepository : StatusBarModeRepository {
+class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepository {
override val isTransientShown = MutableStateFlow(false)
override val isInFullscreenMode = MutableStateFlow(false)
override val statusBarAppearance = MutableStateFlow<StatusBarAppearance?>(null)
override val statusBarMode = MutableStateFlow(StatusBarMode.TRANSPARENT)
- override fun onStatusBarViewInitialized(component: StatusBarFragmentComponent) {}
-
override fun showTransient() {
isTransientShown.value = true
}
@@ -36,3 +36,8 @@
isTransientShown.value = false
}
}
+
+@Module
+interface FakeStatusBarModeRepositoryModule {
+ @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt
index 788e3aa..465b93a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt
@@ -16,7 +16,14 @@
package com.android.systemui.statusbar.notification.data
import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardStateRepositoryModule
+import com.android.systemui.statusbar.notification.data.repository.NotificationStackRepositoryModule
import dagger.Module
-@Module(includes = [FakeNotificationsKeyguardStateRepositoryModule::class])
+@Module(
+ includes =
+ [
+ FakeNotificationsKeyguardStateRepositoryModule::class,
+ NotificationStackRepositoryModule::class,
+ ]
+)
object FakeStatusBarNotificationsDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/FakeStatusBarPhoneDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/FakeStatusBarPhoneDataLayerModule.kt
new file mode 100644
index 0000000..d2c3b7a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/FakeStatusBarPhoneDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.statusbar.phone.data
+
+import com.android.systemui.statusbar.phone.data.repository.FakeDarkIconRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeDarkIconRepositoryModule::class]) object FakeStatusBarPhoneDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt
new file mode 100644
index 0000000..50d3f0a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.statusbar.phone.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+@SysUISingleton
+class FakeDarkIconRepository @Inject constructor() : DarkIconRepository {
+ override val darkState = MutableStateFlow(DarkChange(emptyList(), 0f, 0))
+}
+
+@Module
+interface FakeDarkIconRepositoryModule {
+ @Binds fun bindFake(fake: FakeDarkIconRepository): DarkIconRepository
+}