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

Commit 44c01f4b authored by Chris Göllner's avatar Chris Göllner
Browse files

StatusOverlayHoverListener: use display specific components

Use display specific DarkIconDispatcher and ConfigurationController.

Test: StatusOverlayHoverListenerTest.kt
Test: Manually - Hover the status bar with light and dark themed
      activities on both displays and make sure the correct colors
      are used.
Bug: 369337696
Flag: com.android.systemui.status_bar_connected_displays
Change-Id: I93371fc0d118d15afc1c4efd0795b337a9cf3245
parent f133c63e
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -31,10 +31,13 @@ import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
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
@@ -50,16 +53,18 @@ import org.mockito.Mockito.verify
@SmallTest
class StatusOverlayHoverListenerTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val viewOverlay = mock<ViewGroupOverlay>()
    private val overlayCaptor = argumentCaptor<Drawable>()
    private val darkDispatcher = mock<SysuiDarkIconDispatcher>()
    private val darkChange: MutableStateFlow<DarkChange> = MutableStateFlow(DarkChange.EMPTY)
    private val darkDispatcher = kosmos.sysUiDarkIconDispatcherStore.forDisplay(context.displayId)

    private val factory =
        StatusOverlayHoverListenerFactory(
            context.resources,
            FakeConfigurationController(),
            darkDispatcher
            kosmos.sysUiDarkIconDispatcherStore,
            kosmos.statusBarConfigurationControllerStore,
        )
    private val view = TestableStatusContainer(context, viewOverlay)

@@ -186,7 +191,7 @@ class StatusOverlayHoverListenerTest : SysuiTestCase() {
            /* action= */ action,
            /* x= */ 0f,
            /* y= */ 0f,
            /* metaState= */ 0
            /* metaState= */ 0,
        )
    }
}
+17 −8
Original line number Diff line number Diff line
@@ -28,10 +28,13 @@ import androidx.annotation.ColorInt
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.DarkIconDispatcher
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.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
@@ -40,14 +43,14 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import com.android.app.tracing.coroutines.launchTraced as launch

class StatusOverlayHoverListenerFactory
@Inject
constructor(
    @Main private val resources: Resources,
    private val configurationController: ConfigurationController,
    private val darkIconDispatcher: SysuiDarkIconDispatcher,
    private val darkIconDispatcherStore: SysuiDarkIconDispatcherStore,
    private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
) {

    /** Creates listener always using the same light color for overlay */
@@ -63,7 +66,7 @@ constructor(
     * Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
     */
    fun createDarkAwareListener(view: View) =
        createDarkAwareListener(view, darkIconDispatcher.darkChangeFlow())
        createDarkAwareListener(view, view.darkIconDispatcher.darkChangeFlow())

    /**
     * Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
@@ -78,7 +81,7 @@ constructor(
    ) =
        createDarkAwareListener(
            view,
            darkIconDispatcher.darkChangeFlow(),
            view.darkIconDispatcher.darkChangeFlow(),
            leftHoverMargin,
            rightHoverMargin,
            topHoverMargin,
@@ -92,8 +95,8 @@ constructor(
    fun createDarkAwareListener(view: View, darkFlow: StateFlow<DarkChange>) =
        StatusOverlayHoverListener(
            view,
            configurationController,
            resources,
            view.statusBarConfigurationController,
            view.resources,
            darkFlow.map { toHoverTheme(view, it) },
        )

@@ -107,8 +110,8 @@ constructor(
    ) =
        StatusOverlayHoverListener(
            view,
            configurationController,
            resources,
            view.statusBarConfigurationController,
            view.resources,
            darkFlow.map { toHoverTheme(view, it) },
            leftHoverMargin,
            rightHoverMargin,
@@ -116,6 +119,12 @@ constructor(
            bottomHoverMargin,
        )

    private val View.statusBarConfigurationController
        get() = statusBarConfigurationControllerStore.forDisplay(context.displayId)

    private val View.darkIconDispatcher
        get() = darkIconDispatcherStore.forDisplay(context.displayId)

    private fun toHoverTheme(view: View, darkChange: DarkChange): HoverTheme {
        val calculatedTint = DarkIconDispatcher.getTint(darkChange.areas, view, darkChange.tint)
        // currently calculated tint is either white or some shade of black.
+4 −0
Original line number Diff line number Diff line
@@ -35,3 +35,7 @@ val Kosmos.multiDisplayDarkIconDispatcherStore by
val Kosmos.fakeDarkIconDispatcherStore by Kosmos.Fixture { FakeDarkIconDispatcherStore() }

var Kosmos.darkIconDispatcherStore by Kosmos.Fixture { fakeDarkIconDispatcherStore }

val Kosmos.fakeSysUiDarkIconDispatcherStore by Kosmos.Fixture { FakeSysUiDarkIconDispatcherStore() }

var Kosmos.sysUiDarkIconDispatcherStore by Kosmos.Fixture { fakeSysUiDarkIconDispatcherStore }
+33 −0
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.view.Display
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
import org.mockito.kotlin.mock

class FakeSysUiDarkIconDispatcherStore : SysuiDarkIconDispatcherStore {

    private val perDisplayMocks = mutableMapOf<Int, SysuiDarkIconDispatcher>()

    override val defaultDisplay: SysuiDarkIconDispatcher
        get() = forDisplay(Display.DEFAULT_DISPLAY)

    override fun forDisplay(displayId: Int): SysuiDarkIconDispatcher {
        return perDisplayMocks.computeIfAbsent(displayId) { mock() }
    }
}