1 /* <lambda>null2 * Copyright (C) 2024 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.annotation.SuppressLint 20 import android.content.Context 21 import android.os.Bundle 22 import android.util.Log 23 import android.view.Display 24 import android.view.LayoutInflater 25 import android.view.WindowManager 26 import com.android.app.tracing.coroutines.launchTraced as launch 27 import com.android.systemui.CoreStartable 28 import com.android.systemui.dagger.SysUISingleton 29 import com.android.systemui.dagger.qualifiers.Background 30 import com.android.systemui.display.shared.model.DisplayWindowProperties 31 import com.android.systemui.res.R 32 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround 33 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays 34 import com.android.systemui.utils.windowmanager.WindowManagerUtils 35 import com.google.common.collect.HashBasedTable 36 import com.google.common.collect.Table 37 import java.io.PrintWriter 38 import javax.inject.Inject 39 import kotlinx.coroutines.CoroutineScope 40 41 /** Provides per display instances of [DisplayWindowProperties]. */ 42 interface DisplayWindowPropertiesRepository { 43 44 /** 45 * Returns a [DisplayWindowProperties] instance for a given display id and window type, or null 46 * if no display with the given display id exists. 47 */ 48 fun get( 49 displayId: Int, 50 @WindowManager.LayoutParams.WindowType windowType: Int, 51 ): DisplayWindowProperties? 52 } 53 54 @SysUISingleton 55 class DisplayWindowPropertiesRepositoryImpl 56 @Inject 57 constructor( 58 @Background private val backgroundApplicationScope: CoroutineScope, 59 private val globalContext: Context, 60 private val globalWindowManager: WindowManager, 61 private val globalLayoutInflater: LayoutInflater, 62 private val displayRepository: DisplayRepository, 63 ) : DisplayWindowPropertiesRepository, CoreStartable { 64 65 init { <lambda>null66 check(StatusBarConnectedDisplays.isEnabled || ShadeWindowGoesAround.isEnabled) { 67 "This should be instantiated only when wither StatusBarConnectedDisplays or " + 68 "ShadeWindowGoesAround are enabled." 69 } 70 } 71 72 private val properties: Table<Int, Int, DisplayWindowProperties> = HashBasedTable.create() 73 getnull74 override fun get( 75 displayId: Int, 76 @WindowManager.LayoutParams.WindowType windowType: Int, 77 ): DisplayWindowProperties? { 78 val display = displayRepository.getDisplay(displayId) ?: return null 79 return properties.get(displayId, windowType) 80 ?: create(display, windowType)?.also { properties.put(displayId, windowType, it) } 81 } 82 startnull83 override fun start() { 84 backgroundApplicationScope.launch("DisplayWindowPropertiesRepositoryImpl#start") { 85 displayRepository.displayRemovalEvent.collect { removedDisplayId -> 86 properties.row(removedDisplayId).clear() 87 } 88 } 89 } 90 createnull91 private fun create(display: Display, windowType: Int): DisplayWindowProperties? { 92 val displayId = display.displayId 93 return if (displayId == Display.DEFAULT_DISPLAY) { 94 // For the default display, we can just reuse the global/application properties. 95 // Creating a window context is expensive, therefore we avoid it. 96 DisplayWindowProperties( 97 displayId = displayId, 98 windowType = windowType, 99 context = globalContext, 100 windowManager = globalWindowManager, 101 layoutInflater = globalLayoutInflater, 102 ) 103 } else { 104 val context = createWindowContext(display, windowType) 105 if (context.displayId != display.displayId) { 106 Log.e( 107 TAG, 108 "Returning null because the new context doesn't have the desired display id " + 109 "${display.displayId}. Display was already removed.", 110 ) 111 return null 112 } 113 @SuppressLint("NonInjectedService") // Need to manually get the service 114 val windowManager = WindowManagerUtils.getWindowManager(context) 115 val layoutInflater = LayoutInflater.from(context) 116 DisplayWindowProperties(displayId, windowType, context, windowManager, layoutInflater) 117 } 118 } 119 createWindowContextnull120 private fun createWindowContext(display: Display, windowType: Int): Context = 121 globalContext.createWindowContext(display, windowType, /* options= */ Bundle.EMPTY).also { 122 it.setTheme(R.style.Theme_SystemUI) 123 } 124 dumpnull125 override fun dump(pw: PrintWriter, args: Array<out String>) { 126 pw.write("perDisplayContexts: $properties") 127 } 128 129 private companion object { 130 const val TAG = "DisplayWindowPropsRepo" 131 } 132 } 133