1 /* <lambda>null2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.display.data.repository 18 19 import android.view.IWindowManager 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Background 22 import com.android.systemui.statusbar.CommandQueue 23 import javax.inject.Inject 24 import kotlinx.coroutines.CoroutineScope 25 import kotlinx.coroutines.channels.awaitClose 26 import kotlinx.coroutines.flow.Flow 27 import kotlinx.coroutines.flow.SharingStarted 28 import kotlinx.coroutines.flow.StateFlow 29 import kotlinx.coroutines.flow.callbackFlow 30 import kotlinx.coroutines.flow.distinctUntilChanged 31 import kotlinx.coroutines.flow.map 32 import kotlinx.coroutines.flow.merge 33 import kotlinx.coroutines.flow.scan 34 import kotlinx.coroutines.flow.stateIn 35 36 /** Provides the displays with decorations. */ 37 interface DisplaysWithDecorationsRepository { 38 /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */ 39 val displayIdsWithSystemDecorations: StateFlow<Set<Int>> 40 } 41 42 @SysUISingleton 43 class DisplaysWithDecorationsRepositoryImpl 44 @Inject 45 constructor( 46 private val commandQueue: CommandQueue, 47 private val windowManager: IWindowManager, 48 @Background bgApplicationScope: CoroutineScope, 49 displayRepository: com.android.app.displaylib.DisplayRepository, 50 ) : DisplaysWithDecorationsRepository { 51 <lambda>null52 private val decorationEvents: Flow<Event> = callbackFlow { 53 val callback = 54 object : CommandQueue.Callbacks { 55 override fun onDisplayAddSystemDecorations(displayId: Int) { 56 trySend(Event.Add(displayId)) 57 } 58 59 override fun onDisplayRemoveSystemDecorations(displayId: Int) { 60 trySend(Event.Remove(displayId)) 61 } 62 } 63 commandQueue.addCallback(callback) 64 awaitClose { commandQueue.removeCallback(callback) } 65 } 66 67 private val initialDisplayIdsWithDecorations: Set<Int> = 68 displayRepository.displayIds.value <lambda>null69 .filter { windowManager.shouldShowSystemDecors(it) } 70 .toSet() 71 72 /** 73 * A [StateFlow] that maintains a set of display IDs that should have system decorations. 74 * 75 * Updates to the set are triggered by: 76 * - Adding displays via [CommandQueue.Callbacks.onDisplayAddSystemDecorations]. 77 * - Removing displays via [CommandQueue.Callbacks.onDisplayRemoveSystemDecorations]. 78 * - Removing displays via [displayRemovalEvent] emissions. 79 * 80 * The set is initialized with displays that qualify for system decorations based on 81 * [WindowManager.shouldShowSystemDecors]. 82 */ 83 override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> = <lambda>null84 merge(decorationEvents, displayRepository.displayRemovalEvent.map { Event.Remove(it) }) displayIdsnull85 .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event -> 86 when (event) { 87 is Event.Add -> displayIds + event.displayId 88 is Event.Remove -> displayIds - event.displayId 89 } 90 } 91 .distinctUntilChanged() 92 .stateIn( 93 scope = bgApplicationScope, 94 started = SharingStarted.WhileSubscribed(), 95 initialValue = initialDisplayIdsWithDecorations, 96 ) 97 98 private sealed class Event(val displayId: Int) { 99 class Add(displayId: Int) : Event(displayId) 100 101 class Remove(displayId: Int) : Event(displayId) 102 } 103 } 104