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

Commit 50ef4a0e authored by Nicolò Mazzucato's avatar Nicolò Mazzucato Committed by Android (Google) Code Review
Browse files

Merge "Extract DisplaysWithDecorationsRepository from DisplayRepository" into main

parents d4d65b17 a9fac425
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -80,13 +80,14 @@ class DisplayRepositoryTest : SysuiTestCase() {
                testScope.backgroundScope,
                UnconfinedTestDispatcher(),
            )
        DisplayRepositoryImpl(
        val displaysWithDecorRepository =
            DisplaysWithDecorationsRepositoryImpl(
                commandQueue,
                windowManager,
                testScope.backgroundScope,
                displayRepositoryFromLib,
            )
            .also {
        DisplayRepositoryImpl(displayRepositoryFromLib, displaysWithDecorRepository).also {
            verify(displayManager, never()).registerDisplayListener(any(), any())
            // It needs to be called, just once, for the initial value.
            verify(displayManager).getDisplays()
+7 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import com.android.systemui.display.data.repository.DisplayScopeRepository
import com.android.systemui.display.data.repository.DisplayScopeRepositoryImpl
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepositoryImpl
import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepository
import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepositoryImpl
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
import com.android.systemui.display.data.repository.PerDisplayRepoDumpHelper
@@ -83,6 +85,11 @@ interface DisplayModule {
        impl: DisplayWindowPropertiesRepositoryImpl
    ): DisplayWindowPropertiesRepository

    @Binds
    fun displaysWithDecorationsRepository(
        impl: DisplaysWithDecorationsRepositoryImpl
    ): DisplaysWithDecorationsRepository

    @Binds
    fun dumpRegistrationLambda(helper: PerDisplayRepoDumpHelper): PerDisplayRepository.InitCallback

+12 −82
Original line number Diff line number Diff line
@@ -16,95 +16,25 @@

package com.android.systemui.display.data.repository

import android.annotation.SuppressLint
import android.view.IWindowManager
import com.android.app.displaylib.DisplayRepository as DisplayRepositoryFromLib
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.CommandQueue
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn

/** Repository for providing access to display related information and events. */
interface DisplayRepository : DisplayRepositoryFromLib {

    /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
    val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
}
/**
 * Repository for providing access to display related information and events.
 *
 * This is now just an interface that extends [DisplayRepositoryFromLib] to avoid changing all the
 * imports in sysui using this interface.
 */
interface DisplayRepository : DisplayRepositoryFromLib, DisplaysWithDecorationsRepository

@SysUISingleton
@SuppressLint("SharedFlowCreation")
class DisplayRepositoryImpl
@Inject
constructor(
    private val commandQueue: CommandQueue,
    private val windowManager: IWindowManager,
    @Background bgApplicationScope: CoroutineScope,
    private val displayRepositoryFromLib: com.android.app.displaylib.DisplayRepository,
) : DisplayRepositoryFromLib by displayRepositoryFromLib, DisplayRepository {

    private val decorationEvents: Flow<Event> = callbackFlow {
        val callback =
            object : CommandQueue.Callbacks {
                override fun onDisplayAddSystemDecorations(displayId: Int) {
                    trySend(Event.Add(displayId))
                }

                override fun onDisplayRemoveSystemDecorations(displayId: Int) {
                    trySend(Event.Remove(displayId))
                }
            }
        commandQueue.addCallback(callback)
        awaitClose { commandQueue.removeCallback(callback) }
    }

    private val initialDisplayIdsWithDecorations: Set<Int> =
        displayIds.value.filter { windowManager.shouldShowSystemDecors(it) }.toSet()

    /**
     * A [StateFlow] that maintains a set of display IDs that should have system decorations.
     *
     * Updates to the set are triggered by:
     * - Adding displays via [CommandQueue.Callbacks.onDisplayAddSystemDecorations].
     * - Removing displays via [CommandQueue.Callbacks.onDisplayRemoveSystemDecorations].
     * - Removing displays via [displayRemovalEvent] emissions.
     *
     * The set is initialized with displays that qualify for system decorations based on
     * [WindowManager.shouldShowSystemDecors].
     */
    override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
        merge(decorationEvents, displayRemovalEvent.map { Event.Remove(it) })
            .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event ->
                when (event) {
                    is Event.Add -> displayIds + event.displayId
                    is Event.Remove -> displayIds - event.displayId
                }
            }
            .distinctUntilChanged()
            .stateIn(
                scope = bgApplicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = initialDisplayIdsWithDecorations,
            )

    private sealed class Event(val displayId: Int) {
        class Add(displayId: Int) : Event(displayId)

        class Remove(displayId: Int) : Event(displayId)
    }

    private companion object {
        const val TAG = "DisplayRepository"
    }
}
    private val displaysWithDecorationsRepositoryImpl: DisplaysWithDecorationsRepository,
) :
    DisplayRepositoryFromLib by displayRepositoryFromLib,
    DisplaysWithDecorationsRepository by displaysWithDecorationsRepositoryImpl,
    DisplayRepository
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.display.data.repository

import android.view.IWindowManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.CommandQueue
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn

/** Provides the displays with decorations. */
interface DisplaysWithDecorationsRepository {
    /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
    val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
}

@SysUISingleton
class DisplaysWithDecorationsRepositoryImpl
@Inject
constructor(
    private val commandQueue: CommandQueue,
    private val windowManager: IWindowManager,
    @Background bgApplicationScope: CoroutineScope,
    displayRepository: com.android.app.displaylib.DisplayRepository,
) : DisplaysWithDecorationsRepository {

    private val decorationEvents: Flow<Event> = callbackFlow {
        val callback =
            object : CommandQueue.Callbacks {
                override fun onDisplayAddSystemDecorations(displayId: Int) {
                    trySend(Event.Add(displayId))
                }

                override fun onDisplayRemoveSystemDecorations(displayId: Int) {
                    trySend(Event.Remove(displayId))
                }
            }
        commandQueue.addCallback(callback)
        awaitClose { commandQueue.removeCallback(callback) }
    }

    private val initialDisplayIdsWithDecorations: Set<Int> =
        displayRepository.displayIds.value
            .filter { windowManager.shouldShowSystemDecors(it) }
            .toSet()

    /**
     * A [StateFlow] that maintains a set of display IDs that should have system decorations.
     *
     * Updates to the set are triggered by:
     * - Adding displays via [CommandQueue.Callbacks.onDisplayAddSystemDecorations].
     * - Removing displays via [CommandQueue.Callbacks.onDisplayRemoveSystemDecorations].
     * - Removing displays via [displayRemovalEvent] emissions.
     *
     * The set is initialized with displays that qualify for system decorations based on
     * [WindowManager.shouldShowSystemDecors].
     */
    override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
        merge(decorationEvents, displayRepository.displayRemovalEvent.map { Event.Remove(it) })
            .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event ->
                when (event) {
                    is Event.Add -> displayIds + event.displayId
                    is Event.Remove -> displayIds - event.displayId
                }
            }
            .distinctUntilChanged()
            .stateIn(
                scope = bgApplicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = initialDisplayIdsWithDecorations,
            )

    private sealed class Event(val displayId: Int) {
        class Add(displayId: Int) : Event(displayId)

        class Remove(displayId: Int) : Event(displayId)
    }
}