Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13357d18 authored by Chris Göllner's avatar Chris Göllner
Browse files

Move DarkIconDispatcher into SystemUIPhoneDisplaySubcomponent

This also fixes a race that causes a crash, when DarkIconDispatcher
was requested shortly after a display being removed.

Test: Build & Run
Test: atest SystemUITests
Flag: EXEMPT Dagger change that can't be flagged
Fixes: 428645099
Bug: 417927751
Change-Id: I9866880c1a5b6300fbe1ff1c943849c8f0a56f0f
parent b7c6f872
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.fragments.FragmentHostManager
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.plugins.fakeDarkIconDispatcher
import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
@@ -80,7 +79,6 @@ class StatusBarInitializerTest : SysuiTestCase() {
            componentFactory = mock(HomeStatusBarComponent.Factory::class.java),
            lifecycleListeners = setOf(),
            statusBarModePerDisplayRepository = statusBarModePerDisplayRepository,
            darkIconDispatcher = kosmos.fakeDarkIconDispatcher,
            statusBarConfigurationController = kosmos.statusBarConfigurationController,
        )

+0 −73
Original line number Diff line number Diff line
/*
 * 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 systemDecorationRemovedEvent_stopsInstance() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!

            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)

            verify(instance).stop()
        }
}
+5 −10
Original line number Diff line number Diff line
@@ -32,17 +32,15 @@ import androidx.annotation.ColorInt
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.data.repository.displaySubcomponentPerDisplayRepository
import com.android.systemui.plugins.fakeDarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore
import com.android.systemui.statusbar.data.repository.sysUiDarkIconDispatcherStore
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -56,14 +54,13 @@ class StatusOverlayHoverListenerTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val viewOverlay = mock<ViewGroupOverlay>()
    private val overlayCaptor = argumentCaptor<Drawable>()
    private val darkChange: MutableStateFlow<DarkChange> = MutableStateFlow(DarkChange.EMPTY)
    private val darkDispatcher = kosmos.sysUiDarkIconDispatcherStore.forDisplay(context.displayId)
    private val darkDispatcher = kosmos.fakeDarkIconDispatcher

    private val factory =
        StatusOverlayHoverListenerFactory(
            context.resources,
            FakeConfigurationController(),
            kosmos.sysUiDarkIconDispatcherStore,
            kosmos.displaySubcomponentPerDisplayRepository,
            kosmos.statusBarConfigurationControllerStore,
        )
    private val view = TestableStatusContainer(context, viewOverlay)
@@ -73,7 +70,6 @@ class StatusOverlayHoverListenerTest : SysuiTestCase() {
    @Before
    fun setUp() {
        looper = TestableLooper.get(this)
        whenever(darkDispatcher.darkChangeFlow()).thenReturn(darkChange)
    }

    @Test
@@ -164,8 +160,7 @@ class StatusOverlayHoverListenerTest : SysuiTestCase() {
        get() = (overlayDrawable as PaintDrawable).paint.color

    private fun setIconsTint(@ColorInt color: Int) {
        // passing empty ArrayList is equivalent to just accepting passed color as icons color
        darkChange.value = DarkChange(/* areas= */ ArrayList(), /* darkIntensity= */ 1f, color)
        darkDispatcher.setIconsTint(color)
    }

    private fun TestableStatusContainer.hoverStarted() {
+10 −6
Original line number Diff line number Diff line
@@ -17,7 +17,11 @@
package com.android.systemui.dagger;


import android.view.Display;

import com.android.app.displaylib.PerDisplayRepository;
import com.android.systemui.classifier.FalsingManagerProxy;
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.globalactions.GlobalActionsImpl;
import com.android.systemui.plugins.ActivityStarter;
@@ -27,8 +31,6 @@ import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
import com.android.systemui.statusbar.data.repository.SysuiDarkIconDispatcherStore;
import com.android.systemui.statusbar.phone.ActivityStarterImpl;
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
import com.android.systemui.volume.VolumeDialogControllerImpl;
@@ -52,15 +54,17 @@ public abstract class PluginModule {
    /** */
    @Provides
    @SysUISingleton
    static DarkIconDispatcher provideDarkIconDispatcher(DarkIconDispatcherStore store) {
        return store.getDefaultDisplay();
    static DarkIconDispatcher provideDarkIconDispatcher(
            PerDisplayRepository<SystemUIDisplaySubcomponent> displaySubComponentRepository) {
        return displaySubComponentRepository.get(Display.DEFAULT_DISPLAY).getDarkIconDispatcher();
    }

    @Provides
    @SysUISingleton
    static SysuiDarkIconDispatcher provideSysuiDarkIconDispatcher(
            SysuiDarkIconDispatcherStore store) {
        return store.getDefaultDisplay();
            PerDisplayRepository<SystemUIDisplaySubcomponent> displaySubComponentRepository) {
        return displaySubComponentRepository.get(
                Display.DEFAULT_DISPLAY).getSysUiDarkIconDispatcher();
    }

    /** */
+8 −11
Original line number Diff line number Diff line
@@ -31,7 +31,8 @@ import com.android.systemui.display.domain.interactor.DisplayStateInteractor
import com.android.systemui.display.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.statusbar.dagger.StatusBarPerDisplayModule
import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
import com.android.systemui.statusbar.pipeline.shared.ui.composable.StatusBarRootFactory
import dagger.Binds
import dagger.Module
@@ -62,17 +63,13 @@ interface PerDisplayCommonModule {
    @DisplayAware
    fun statusBarRootFactory(statusBarRootFactory: StatusBarRootFactory): StatusBarRootFactory

    companion object {
        @Provides
        @PerDisplaySingleton
    @Binds @DisplayAware fun darkIconDispatcher(impl: DarkIconDispatcherImpl): DarkIconDispatcher

    @Binds
    @DisplayAware
        fun darkIconDispatcher(
            @DisplayId displayId: Int,
            darkIconDispatcherStore: DarkIconDispatcherStore,
        ): DarkIconDispatcher {
            return darkIconDispatcherStore.forDisplay(displayId)
                ?: error("No DarkIconDispatcher for display $displayId")
        }
    fun sysUiDarkIconDispatcher(impl: DarkIconDispatcherImpl): SysuiDarkIconDispatcher

    companion object {

        @Provides
        @PerDisplaySingleton
Loading