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.shade.domain.interactor 18 19 import android.content.Context 20 import android.util.Log 21 import android.view.Display 22 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL 23 import com.android.app.tracing.coroutines.launchTraced 24 import com.android.app.tracing.traceSection 25 import com.android.systemui.CoreStartable 26 import com.android.systemui.dagger.SysUISingleton 27 import com.android.systemui.dagger.qualifiers.Background 28 import com.android.systemui.dagger.qualifiers.Main 29 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository 30 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository 31 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround 32 import javax.inject.Inject 33 import javax.inject.Provider 34 import kotlinx.coroutines.CoroutineScope 35 import kotlinx.coroutines.flow.collectLatest 36 import kotlinx.coroutines.flow.filter 37 38 /** Provides the correct context to show dialogs on the shade window, whenever it moves. */ 39 interface ShadeDialogContextInteractor { 40 /** Context usable to create dialogs on the notification shade display. */ 41 val context: Context 42 } 43 44 @SysUISingleton 45 class ShadeDialogContextInteractorImpl 46 @Inject 47 constructor( 48 @Main private val defaultContext: Context, 49 private val displayWindowPropertyRepository: Provider<DisplayWindowPropertiesRepository>, 50 private val shadeDisplaysRepository: Provider<ShadeDisplaysRepository>, 51 @Background private val bgScope: CoroutineScope, 52 ) : CoreStartable, ShadeDialogContextInteractor { 53 startnull54 override fun start() { 55 if (ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()) return 56 bgScope.launchTraced(TAG) { 57 shadeDisplaysRepository 58 .get() 59 .displayId 60 // No need for default display pre-warming. 61 .filter { it != Display.DEFAULT_DISPLAY } 62 .collectLatest { displayId -> 63 // Prewarms the context in the background every time the display changes. 64 // In this way, there will be no main thread delays when a dialog is shown. 65 getContextOrDefault(displayId) 66 } 67 } 68 } 69 70 override val context: Context 71 get() { 72 if (!ShadeWindowGoesAround.isEnabled) { 73 return defaultContext 74 } 75 val displayId = shadeDisplaysRepository.get().displayId.value 76 return getContextOrDefault(displayId) 77 } 78 getContextOrDefaultnull79 private fun getContextOrDefault(displayId: Int): Context { 80 return try { 81 traceSection({ "Getting dialog context for displayId=$displayId" }) { 82 val displayWindowProperties = 83 displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE) 84 if (displayWindowProperties == null) { 85 Log.e( 86 TAG, 87 "DisplayWindowPropertiesRepository returned null for display $displayId. Returning default one", 88 ) 89 defaultContext 90 } else { 91 displayWindowProperties.context 92 } 93 } 94 } catch (e: Exception) { 95 // This can happen if the display was disconnected in the meantime. 96 Log.e( 97 TAG, 98 "Couldn't get dialog context for displayId=$displayId. Returning default one", 99 e, 100 ) 101 defaultContext 102 } 103 } 104 105 private companion object { 106 const val TAG = "ShadeDialogContextRepo" 107 const val DIALOG_WINDOW_TYPE = TYPE_STATUS_BAR_SUB_PANEL 108 } 109 } 110