diff options
| author | 2024-11-06 15:24:40 +0000 | |
|---|---|---|
| committer | 2024-11-06 15:24:40 +0000 | |
| commit | 6a1ca545cc85b95953ff353d2460615fac61a85e (patch) | |
| tree | 3570914e301a562425a54943f977e5066f808b28 | |
| parent | 6e3cd07e02941a73ac217d57a16eca689308b5a7 (diff) | |
| parent | 57807815ec6ff1a9ef35decb8fba75932479fcd0 (diff) | |
Merge changes Icbc6fcac,I3651e364 into main
* changes:
Introduce DarkIconDispatcherStore for multiple displays
Prepare DarkIconDispatcher for multiple displays
7 files changed, 303 insertions, 11 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt new file mode 100644 index 000000000000..a2c3c66f4448 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt @@ -0,0 +1,73 @@ +/* + * 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.statusbar.data.repository + +import android.platform.test.annotations.EnableFlags +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.testKosmos +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) +class MultiDisplayDarkIconDispatcherStoreTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val testScope = kosmos.testScope + private val fakeDisplayRepository = kosmos.displayRepository + + // Lazy so that @EnableFlags has time to run before underTest is instantiated. + private val underTest by lazy { kosmos.multiDisplayDarkIconDispatcherStore } + + @Before + fun start() { + underTest.start() + } + + @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) } + + @Test + fun beforeDisplayRemoved_doesNotStopInstances() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + verify(instance, never()).stop() + } + + @Test + fun displayRemoved_stopsInstance() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY) + + verify(instance).stop() + } +} 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 403c7c500426..43185fd08613 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java @@ -36,6 +36,9 @@ import java.util.Collection; public interface DarkIconDispatcher { int VERSION = 2; + /** Called when work should stop and resources should be cleaned up. */ + default void stop() {} + /** * Sets the dark area so {@link #applyDark} only affects the icons in the specified area. * diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java index d727a70de377..4149f9ae00c2 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java @@ -16,7 +16,10 @@ package com.android.systemui.dagger; +import android.content.Context; + import com.android.systemui.classifier.FalsingManagerProxy; +import com.android.systemui.dagger.qualifiers.Default; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.globalactions.GlobalActionsImpl; import com.android.systemui.plugins.ActivityStarter; @@ -33,11 +36,12 @@ import com.android.systemui.volume.VolumeDialogControllerImpl; import dagger.Binds; import dagger.Module; +import dagger.Provides; /** * Module for binding Plugin implementations. * - * TODO(b/166258224): Many of these should be moved closer to their implementations. + * <p>TODO(b/166258224): Many of these should be moved closer to their implementations. */ @Module public abstract class PluginModule { @@ -47,12 +51,22 @@ public abstract class PluginModule { abstract ActivityStarter provideActivityStarter(ActivityStarterImpl activityStarterImpl); /** */ + @Provides + @SysUISingleton + @Default + static DarkIconDispatcherImpl darkIconDispatcherImpl( + DarkIconDispatcherImpl.Factory factory, Context context) { + return factory.create(context.getDisplayId(), context); + } + + /** */ @Binds - abstract DarkIconDispatcher provideDarkIconDispatcher(DarkIconDispatcherImpl controllerImpl); + abstract DarkIconDispatcher provideDarkIconDispatcher( + @Default DarkIconDispatcherImpl controllerImpl); @Binds abstract SysuiDarkIconDispatcher provideSysuiDarkIconDispatcher( - DarkIconDispatcherImpl controllerImpl); + @Default DarkIconDispatcherImpl controllerImpl); /** */ @Binds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt index 39de28e7cb49..27d815190d85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.statusbar.data +import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStoreModule import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule import com.android.systemui.statusbar.data.repository.LightBarControllerStoreModule import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule @@ -28,6 +29,7 @@ import dagger.Module @Module( includes = [ + DarkIconDispatcherStoreModule::class, KeyguardStatusBarRepositoryModule::class, LightBarControllerStoreModule::class, RemoteInputRepositoryModule::class, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt new file mode 100644 index 000000000000..8183a487cee2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt @@ -0,0 +1,142 @@ +/* + * 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.statusbar.data.repository + +import android.content.Context +import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.display.data.repository.DisplayRepository +import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository +import com.android.systemui.display.data.repository.PerDisplayStore +import com.android.systemui.display.data.repository.PerDisplayStoreImpl +import com.android.systemui.display.data.repository.SingleDisplayStore +import com.android.systemui.plugins.DarkIconDispatcher +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl +import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher +import dagger.Binds +import dagger.Lazy +import dagger.Module +import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope + +/** Provides per display instances of [DarkIconDispatcher]. */ +interface DarkIconDispatcherStore : PerDisplayStore<DarkIconDispatcher> + +/** Provides per display instances of [SysuiDarkIconDispatcher]. */ +interface SysuiDarkIconDispatcherStore : PerDisplayStore<SysuiDarkIconDispatcher> + +/** + * Multi display implementation that should be used when the [StatusBarConnectedDisplays] flag is + * enabled. + */ +@SysUISingleton +class MultiDisplayDarkIconDispatcherStore +@Inject +constructor( + @Background backgroundApplicationScope: CoroutineScope, + displayRepository: DisplayRepository, + private val factory: DarkIconDispatcherImpl.Factory, + private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository, +) : + SysuiDarkIconDispatcherStore, + PerDisplayStoreImpl<SysuiDarkIconDispatcher>(backgroundApplicationScope, displayRepository) { + + init { + StatusBarConnectedDisplays.assertInNewMode() + } + + override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher { + val properties = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) + return factory.create(displayId, properties.context) + } + + override suspend fun onDisplayRemovalAction(instance: SysuiDarkIconDispatcher) { + instance.stop() + } + + override val instanceClass = SysuiDarkIconDispatcher::class.java +} + +/** + * Single display implementation that should be used when the [StatusBarConnectedDisplays] flag is + * disabled. + */ +@SysUISingleton +class SingleDisplayDarkIconDispatcherStore +@Inject +constructor(factory: DarkIconDispatcherImpl.Factory, context: Context) : + SysuiDarkIconDispatcherStore, + PerDisplayStore<SysuiDarkIconDispatcher> by SingleDisplayStore( + defaultInstance = factory.create(context.displayId, context) + ) { + + init { + StatusBarConnectedDisplays.assertInLegacyMode() + } +} + +/** Extra implementation that simply implements the [DarkIconDispatcherStore] interface. */ +@SysUISingleton +class DarkIconDispatcherStoreImpl +@Inject +constructor(private val store: SysuiDarkIconDispatcherStore) : DarkIconDispatcherStore { + override val defaultDisplay: DarkIconDispatcher + get() = store.defaultDisplay + + override fun forDisplay(displayId: Int): DarkIconDispatcher = store.forDisplay(displayId) +} + +@Module +interface DarkIconDispatcherStoreModule { + + @Binds fun store(impl: DarkIconDispatcherStoreImpl): DarkIconDispatcherStore + + companion object { + @Provides + @SysUISingleton + fun sysUiStore( + singleDisplayLazy: Lazy<SingleDisplayDarkIconDispatcherStore>, + multiDisplayLazy: Lazy<MultiDisplayDarkIconDispatcherStore>, + ): SysuiDarkIconDispatcherStore { + return if (StatusBarConnectedDisplays.isEnabled) { + multiDisplayLazy.get() + } else { + singleDisplayLazy.get() + } + } + + @Provides + @SysUISingleton + @IntoMap + @ClassKey(DarkIconDispatcherStore::class) + fun storeAsCoreStartable( + multiDisplayLazy: Lazy<MultiDisplayDarkIconDispatcherStore> + ): CoreStartable { + return if (StatusBarConnectedDisplays.isEnabled) { + multiDisplayLazy.get() + } else { + CoreStartable.NOP + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java index 398c1d43d4fc..90b591f173f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java @@ -23,11 +23,15 @@ import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Rect; import android.util.ArrayMap; +import android.view.Display; import android.widget.ImageView; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + import kotlinx.coroutines.flow.FlowKt; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.flow.StateFlow; @@ -36,17 +40,15 @@ import kotlinx.coroutines.flow.StateFlowKt; import java.io.PrintWriter; import java.util.ArrayList; -import javax.inject.Inject; - /** */ -@SysUISingleton public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher, LightBarTransitionsController.DarkIntensityApplier { private final LightBarTransitionsController mTransitionsController; private final ArrayList<Rect> mTintAreas = new ArrayList<>(); private final ArrayMap<Object, DarkReceiver> mReceivers = new ArrayMap<>(); + private final DumpManager mDumpManager; private int mIconTint = DEFAULT_ICON_TINT; private int mContrastTint = DEFAULT_INVERSE_ICON_TINT; @@ -61,14 +63,25 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher, private final MutableStateFlow<DarkChange> mDarkChangeFlow = StateFlowKt.MutableStateFlow( DarkChange.EMPTY); + private final String mDumpableName; + + /** */ + @AssistedFactory + @FunctionalInterface + public interface Factory { + /** */ + DarkIconDispatcherImpl create(int displayId, Context context); + } + /** */ - @Inject + @AssistedInject public DarkIconDispatcherImpl( - Context context, + @Assisted int displayId, + @Assisted Context context, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, DumpManager dumpManager) { - + mDumpManager = dumpManager; if (newStatusBarIcons()) { mDarkModeIconColorSingleTone = Color.BLACK; mLightModeIconColorSingleTone = Color.WHITE; @@ -81,7 +94,19 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher, mTransitionsController = lightBarTransitionsControllerFactory.create(this); - dumpManager.registerDumpable(getClass().getSimpleName(), this); + mDumpableName = getDumpableName(displayId); + dumpManager.registerNormalDumpable(mDumpableName, this); + } + + @Override + public void stop() { + mDumpManager.unregisterDumpable(mDumpableName); + } + + private String getDumpableName(int displayId) { + String dumpableNameSuffix = + displayId == Display.DEFAULT_DISPLAY ? "" : String.valueOf(displayId); + return getClass().getSimpleName() + dumpableNameSuffix; } public LightBarTransitionsController getTransitionsController() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStoreKosmos.kt new file mode 100644 index 000000000000..6f723fecf7cd --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStoreKosmos.kt @@ -0,0 +1,33 @@ +/* + * 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.statusbar.data.repository + +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayWindowPropertiesRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import org.mockito.kotlin.mock + +val Kosmos.multiDisplayDarkIconDispatcherStore by + Kosmos.Fixture { + MultiDisplayDarkIconDispatcherStore( + backgroundApplicationScope = applicationCoroutineScope, + displayRepository = displayRepository, + factory = { _, _ -> mock() }, + displayWindowPropertiesRepository = displayWindowPropertiesRepository, + ) + } |