Loading packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -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() Loading packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt +7 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -83,6 +85,11 @@ interface DisplayModule { impl: DisplayWindowPropertiesRepositoryImpl ): DisplayWindowPropertiesRepository @Binds fun displaysWithDecorationsRepository( impl: DisplaysWithDecorationsRepositoryImpl ): DisplaysWithDecorationsRepository @Binds fun dumpRegistrationLambda(helper: PerDisplayRepoDumpHelper): PerDisplayRepository.InitCallback Loading packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +12 −82 Original line number Diff line number Diff line Loading @@ -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 packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt 0 → 100644 +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) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -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() Loading
packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt +7 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -83,6 +85,11 @@ interface DisplayModule { impl: DisplayWindowPropertiesRepositoryImpl ): DisplayWindowPropertiesRepository @Binds fun displaysWithDecorationsRepository( impl: DisplaysWithDecorationsRepositoryImpl ): DisplaysWithDecorationsRepository @Binds fun dumpRegistrationLambda(helper: PerDisplayRepoDumpHelper): PerDisplayRepository.InitCallback Loading
packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +12 −82 Original line number Diff line number Diff line Loading @@ -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
packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt 0 → 100644 +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) } }