diff options
| author | 2024-09-03 17:52:36 +0000 | |
|---|---|---|
| committer | 2024-09-03 17:52:36 +0000 | |
| commit | 782ffd0bc9ca647b0fec87afe7d779399605df0a (patch) | |
| tree | 730d77bb7eb926a10f87ac79216ab8cec4a8ac1d | |
| parent | 9e6ddb47d6b833e81061087de2f75b670a391b69 (diff) | |
| parent | de0b1074196f089ec0d1ee01d01671bc14fed186 (diff) | |
Merge "Allow multiple annotated configuration controllers in sysui" into main
9 files changed, 183 insertions, 63 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt index 578389b57a99..13f6bba01135 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt @@ -23,31 +23,72 @@ import androidx.annotation.ColorInt import androidx.annotation.DimenRes import androidx.annotation.LayoutRes 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 dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge +interface ConfigurationState { + /** + * 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> + + /** + * 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 getDimensionPixelOffset(@DimenRes id: Int): Flow<Int> + + /** + * 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> + + /** + * Returns a [Flow] that emits a [View] that is re-inflated as necessary to remain in sync with + * the device configuration. + * + * @see LayoutInflater.inflate + */ + @Suppress("UNCHECKED_CAST") + fun <T : View> inflateLayout( + @LayoutRes id: Int, + root: ViewGroup?, + attachToRoot: Boolean, + ): Flow<T> +} + /** Configuration-aware-state-tracking utilities. */ -class ConfigurationState -@Inject +class ConfigurationStateImpl +@AssistedInject constructor( - private val configurationController: ConfigurationController, - @Application private val context: Context, - private val layoutInflater: LayoutInflater, -) { + @Assisted private val configurationController: ConfigurationController, + @Assisted private val context: Context, +) : ConfigurationState { + + private val layoutInflater = LayoutInflater.from(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> { + override fun getDimensionPixelSize(@DimenRes id: Int): Flow<Int> { return configurationController.onDensityOrFontScaleChanged.emitOnStart().map { context.resources.getDimensionPixelSize(id) } @@ -59,7 +100,7 @@ constructor( * * @see android.content.res.Resources.getDimensionPixelSize */ - fun getDimensionPixelOffset(@DimenRes id: Int): Flow<Int> { + override fun getDimensionPixelOffset(@DimenRes id: Int): Flow<Int> { return configurationController.onDensityOrFontScaleChanged.emitOnStart().map { context.resources.getDimensionPixelOffset(id) } @@ -70,7 +111,7 @@ constructor( * * @see Utils.getColorAttrDefaultColor */ - fun getColorAttr(@AttrRes id: Int, @ColorInt defaultValue: Int): Flow<Int> { + override fun getColorAttr(@AttrRes id: Int, @ColorInt defaultValue: Int): Flow<Int> { return configurationController.onThemeChanged.emitOnStart().map { Utils.getColorAttrDefaultColor(context, id, defaultValue) } @@ -83,7 +124,7 @@ constructor( * @see LayoutInflater.inflate */ @Suppress("UNCHECKED_CAST") - fun <T : View> inflateLayout( + override fun <T : View> inflateLayout( @LayoutRes id: Int, root: ViewGroup?, attachToRoot: Boolean, @@ -97,4 +138,16 @@ constructor( .emitOnStart() .map { layoutInflater.inflate(id, root, attachToRoot) as T } } + + @AssistedFactory + interface Factory { + /** + * Creates a configurationState for a given context. The [configurationController] is + * supposed to give config events specific for that context. + */ + fun create( + context: Context, + configurationController: ConfigurationController + ): ConfigurationStateImpl + } } diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt new file mode 100644 index 000000000000..b36da3bfcd26 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.common.ui + +import android.content.Context +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.statusbar.policy.ConfigurationController +import dagger.Binds +import dagger.Module +import dagger.Provides +import javax.inject.Qualifier + +/** + * Annotates elements that provide information from the global configuration. + * + * The global configuration is the one associted with the main display. Secondary displays will + * apply override to the global configuration. Elements annotated with this shouldn't be used for + * secondary displays. + */ +@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class GlobalConfig + +@Module +interface ConfigurationStateModule { + + /** + * Deprecated: [ConfigurationState] should be injected only with the correct annotation. For + * now, without annotation the global config associated state is provided. + */ + @Binds + fun provideGlobalConfigurationState( + @GlobalConfig configurationState: ConfigurationState + ): ConfigurationState + + companion object { + @SysUISingleton + @Provides + @GlobalConfig + fun provideGlobalConfigurationState( + configStateFactory: ConfigurationStateImpl.Factory, + configurationController: ConfigurationController, + @Application context: Context, + ): ConfigurationState { + return configStateFactory.create(context, configurationController) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 1dd37222f29b..3fe6669de556 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -21,6 +21,7 @@ import com.android.systemui.CoreStartable; import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactoryBase; +import com.android.systemui.common.ui.GlobalConfig; import com.android.systemui.dagger.qualifiers.PerUser; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; @@ -127,6 +128,7 @@ public interface SysUIComponent { * Creates a ContextComponentHelper. */ @SysUISingleton + @GlobalConfig ConfigurationController getConfigurationController(); /** diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 411cbd511a22..b55108d6ab1d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -48,6 +48,7 @@ import com.android.systemui.brightness.dagger.ScreenBrightnessModule; import com.android.systemui.classifier.FalsingModule; import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule; import com.android.systemui.common.data.CommonDataLayerModule; +import com.android.systemui.common.ui.ConfigurationStateModule; import com.android.systemui.common.usagestats.data.CommonUsageStatsDataLayerModule; import com.android.systemui.communal.dagger.CommunalModule; import com.android.systemui.complication.dagger.ComplicationComponent; @@ -207,6 +208,7 @@ import javax.inject.Named; ClockRegistryModule.class, CommunalModule.class, CommonDataLayerModule.class, + ConfigurationStateModule.class, CommonUsageStatsDataLayerModule.class, ConfigurationControllerModule.class, ConnectivityModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 9b1ca1ec0558..64402052c984 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -122,8 +122,10 @@ interface MediaProjectionAppSelectorModule { @Provides @MediaProjectionAppSelector @MediaProjectionAppSelectorScope - fun bindConfigurationController(context: Context): ConfigurationController = - ConfigurationControllerImpl(context) + fun bindConfigurationController( + context: Context, + configurationControlleFactory: ConfigurationControllerImpl.Factory + ): ConfigurationController = configurationControlleFactory.create(context) @Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt index 2e1ab383538f..bb5aa23fee28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt @@ -20,16 +20,17 @@ import android.content.res.Configuration import android.graphics.Rect import android.os.LocaleList import android.view.View.LAYOUT_DIRECTION_RTL -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener -import javax.inject.Inject +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject -@SysUISingleton -class ConfigurationControllerImpl @Inject constructor( - @Application context: Context, - ) : ConfigurationController { +class ConfigurationControllerImpl +@AssistedInject +constructor( + @Assisted private val context: Context, +) : ConfigurationController { private val listeners: MutableList<ConfigurationListener> = ArrayList() private val lastConfig = Configuration() @@ -40,18 +41,17 @@ class ConfigurationControllerImpl @Inject constructor( private val inCarMode: Boolean private var uiMode: Int = 0 private var localeList: LocaleList? = null - private val context: Context private var layoutDirection: Int private var orientation = Configuration.ORIENTATION_UNDEFINED init { val currentConfig = context.resources.configuration - this.context = context fontScale = currentConfig.fontScale density = currentConfig.densityDpi smallestScreenWidth = currentConfig.smallestScreenWidthDp maxBounds.set(currentConfig.windowConfiguration.maxBounds) - inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK == + inCarMode = + currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK == Configuration.UI_MODE_TYPE_CAR uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK localeList = currentConfig.locales @@ -60,29 +60,20 @@ class ConfigurationControllerImpl @Inject constructor( override fun notifyThemeChanged() { // Avoid concurrent modification exception - val listeners = synchronized(this.listeners) { - ArrayList(this.listeners) - } + val listeners = synchronized(this.listeners) { ArrayList(this.listeners) } - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onThemeChanged() - } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onThemeChanged() } } override fun onConfigurationChanged(newConfig: Configuration) { // Avoid concurrent modification exception - val listeners = synchronized(this.listeners) { - ArrayList(this.listeners) - } - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onConfigChanged(newConfig) - } + val listeners = synchronized(this.listeners) { ArrayList(this.listeners) } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onConfigChanged(newConfig) } val fontScale = newConfig.fontScale val density = newConfig.densityDpi val uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK val uiModeChanged = uiMode != this.uiMode - if (density != this.density || fontScale != this.fontScale || - inCarMode && uiModeChanged) { + if (density != this.density || fontScale != this.fontScale || inCarMode && uiModeChanged) { listeners.filterForEach({ this.listeners.contains(it) }) { it.onDensityOrFontScaleChanged() } @@ -105,17 +96,13 @@ class ConfigurationControllerImpl @Inject constructor( // would be a direct reference to windowConfiguration.maxBounds, so the if statement // above would always fail. See b/245799099 for more information. this.maxBounds.set(maxBounds) - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onMaxBoundsChanged() - } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onMaxBoundsChanged() } } val localeList = newConfig.locales if (localeList != this.localeList) { this.localeList = localeList - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onLocaleListChanged() - } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onLocaleListChanged() } } if (uiModeChanged) { @@ -124,9 +111,7 @@ class ConfigurationControllerImpl @Inject constructor( context.theme.applyStyle(context.themeResId, true) this.uiMode = uiMode - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onUiModeChanged() - } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onUiModeChanged() } } if (layoutDirection != newConfig.layoutDirection) { @@ -137,9 +122,7 @@ class ConfigurationControllerImpl @Inject constructor( } if (lastConfig.updateFrom(newConfig) and ActivityInfo.CONFIG_ASSETS_PATHS != 0) { - listeners.filterForEach({ this.listeners.contains(it) }) { - it.onThemeChanged() - } + listeners.filterForEach({ this.listeners.contains(it) }) { it.onThemeChanged() } } val newOrientation = newConfig.orientation @@ -152,16 +135,12 @@ class ConfigurationControllerImpl @Inject constructor( } override fun addCallback(listener: ConfigurationListener) { - synchronized(listeners) { - listeners.add(listener) - } + synchronized(listeners) { listeners.add(listener) } listener.onDensityOrFontScaleChanged() } override fun removeCallback(listener: ConfigurationListener) { - synchronized(listeners) { - listeners.remove(listener) - } + synchronized(listeners) { listeners.remove(listener) } } override fun isLayoutRtl(): Boolean { @@ -176,6 +155,15 @@ class ConfigurationControllerImpl @Inject constructor( else -> "err" } } + + @AssistedFactory + interface Factory { + /** + * Creates a [ConfigurationController] that uses [context] to resolve the current + * configuration and resources. + */ + fun create(context: Context): ConfigurationControllerImpl + } } // This could be done with a Collection.filter and Collection.forEach, but Collection.filter diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt index 90ebaf269a39..8f4279e80376 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import com.android.systemui.CoreStartable +import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener @@ -26,7 +27,7 @@ import javax.inject.Inject class ConfigurationControllerStartable @Inject constructor( - private val configurationController: ConfigurationController, + @GlobalConfig private val configurationController: ConfigurationController, private val listeners: Set<@JvmSuppressWildcards ConfigurationListener> ) : CoreStartable { override fun start() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index 6cebcbd2731a..b81af86b0779 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -23,7 +23,9 @@ import android.os.UserManager; import com.android.internal.R; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.settingslib.notification.modes.ZenIconLoader; +import com.android.systemui.common.ui.GlobalConfig; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.log.LogBuffer; @@ -103,9 +105,12 @@ public interface StatusBarPolicyModule { @Binds CastController provideCastController(CastControllerImpl controllerImpl); - /** */ + /** + * @deprecated: unscoped configuration controller shouldn't be injected as it might lead to + * wrong updates in case of secondary displays. + */ @Binds - ConfigurationController bindConfigurationController(ConfigurationControllerImpl impl); + ConfigurationController bindConfigurationController(@GlobalConfig ConfigurationController impl); /** */ @Binds @@ -181,6 +186,15 @@ public interface StatusBarPolicyModule { DevicePostureControllerImpl devicePostureControllerImpl); /** */ + @Provides + @SysUISingleton + @GlobalConfig + static ConfigurationController provideGlobalConfigurationController( + @Application Context context, ConfigurationControllerImpl.Factory factory) { + return factory.create(context); + } + + /** */ @SysUISingleton @Provides static AccessPointControllerImpl provideAccessPointControllerImpl( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt index 86a8ae5f9cf4..1ef3464e2b99 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt @@ -17,11 +17,8 @@ package com.android.systemui.common.ui import android.content.applicationContext -import android.view.layoutInflater import com.android.systemui.kosmos.Kosmos import com.android.systemui.statusbar.policy.configurationController val Kosmos.configurationState: ConfigurationState by - Kosmos.Fixture { - ConfigurationState(configurationController, applicationContext, layoutInflater) - } + Kosmos.Fixture { ConfigurationStateImpl(configurationController, applicationContext) } |