• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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