1 /*
<lambda>null2  * Copyright (C) 2021 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.statusbar.notification.collection.coordinator
18 
19 import android.util.Log
20 import com.android.internal.widget.MessagingGroup
21 import com.android.internal.widget.MessagingMessage
22 import com.android.keyguard.KeyguardUpdateMonitor
23 import com.android.keyguard.KeyguardUpdateMonitorCallback
24 import com.android.systemui.statusbar.NotificationLockscreenUserManager
25 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
26 import com.android.systemui.statusbar.notification.ColorUpdateLogger
27 import com.android.systemui.statusbar.notification.collection.NotifPipeline
28 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
29 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
30 import com.android.systemui.statusbar.policy.ConfigurationController
31 import com.android.systemui.util.Compile
32 import com.android.app.tracing.traceSection
33 import javax.inject.Inject
34 
35 /**
36  * A coordinator which ensures that notifications within the new pipeline are correctly inflated
37  * for the current uiMode and screen properties; additionally deferring those changes when a user
38  * change is in progress until that process has completed.
39  */
40 @CoordinatorScope
41 class ViewConfigCoordinator @Inject internal constructor(
42     private val mConfigurationController: ConfigurationController,
43     private val mLockscreenUserManager: NotificationLockscreenUserManager,
44     private val mGutsManager: NotificationGutsManager,
45     private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor,
46     private val colorUpdateLogger: ColorUpdateLogger,
47 ) : Coordinator, ConfigurationController.ConfigurationListener {
48 
49     private var mIsSwitchingUser = false
50     private var mReinflateNotificationsOnUserSwitched = false
51     private var mDispatchUiModeChangeOnUserSwitched = false
52     private var mPipeline: NotifPipeline? = null
53 
54     private val mKeyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
55         override fun onUserSwitching(userId: Int) {
56             colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitching()")
57             log { "ViewConfigCoordinator.onUserSwitching(userId=$userId)" }
58             mIsSwitchingUser = true
59         }
60 
61         override fun onUserSwitchComplete(userId: Int) {
62             colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitchComplete()")
63             log { "ViewConfigCoordinator.onUserSwitchComplete(userId=$userId)" }
64             mIsSwitchingUser = false
65             applyChangesOnUserSwitched()
66         }
67     }
68 
69     private val mUserChangedListener = object : UserChangedListener {
70         override fun onUserChanged(userId: Int) {
71             colorUpdateLogger.logTriggerEvent("VCC.mUserChangedListener.onUserChanged()")
72             log { "ViewConfigCoordinator.onUserChanged(userId=$userId)" }
73             applyChangesOnUserSwitched()
74         }
75     }
76 
77     override fun attach(pipeline: NotifPipeline) {
78         mPipeline = pipeline
79         mLockscreenUserManager.addUserChangedListener(mUserChangedListener)
80         mConfigurationController.addCallback(this)
81         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback)
82     }
83 
84     override fun onDensityOrFontScaleChanged() {
85         colorUpdateLogger.logTriggerEvent("VCC.onDensityOrFontScaleChanged()")
86         log {
87             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
88             "ViewConfigCoordinator.onDensityOrFontScaleChanged()" +
89                     " isSwitchingUser=$mIsSwitchingUser" +
90                     " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
91         }
92         MessagingMessage.dropCache()
93         MessagingGroup.dropCache()
94         if (!mIsSwitchingUser) {
95             updateNotificationsOnDensityOrFontScaleChanged()
96         } else {
97             mReinflateNotificationsOnUserSwitched = true
98         }
99     }
100 
101     override fun onUiModeChanged() {
102         colorUpdateLogger.logTriggerEvent("VCC.onUiModeChanged()")
103         log {
104             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
105             "ViewConfigCoordinator.onUiModeChanged()" +
106                     " isSwitchingUser=$mIsSwitchingUser" +
107                     " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
108         }
109         if (!mIsSwitchingUser) {
110             updateNotificationsOnUiModeChanged()
111         } else {
112             mDispatchUiModeChangeOnUserSwitched = true
113         }
114     }
115 
116     override fun onThemeChanged() {
117         colorUpdateLogger.logTriggerEvent("VCC.onThemeChanged()")
118         onDensityOrFontScaleChanged()
119     }
120 
121     private fun applyChangesOnUserSwitched() {
122         colorUpdateLogger.logEvent("VCC.applyChangesOnUserSwitched()")
123         if (mReinflateNotificationsOnUserSwitched) {
124             updateNotificationsOnDensityOrFontScaleChanged()
125             mReinflateNotificationsOnUserSwitched = false
126         }
127         if (mDispatchUiModeChangeOnUserSwitched) {
128             updateNotificationsOnUiModeChanged()
129             mDispatchUiModeChangeOnUserSwitched = false
130         }
131     }
132 
133     private fun updateNotificationsOnUiModeChanged() {
134         colorUpdateLogger.logEvent("VCC.updateNotificationsOnUiModeChanged()",
135                 "mode=" + mConfigurationController.nightModeName)
136         log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
137         traceSection("updateNotifOnUiModeChanged") {
138             mPipeline?.allNotifs?.forEach { entry ->
139                 entry.row?.onUiModeChanged()
140             }
141         }
142     }
143 
144     private fun updateNotificationsOnDensityOrFontScaleChanged() {
145         colorUpdateLogger.logEvent("VCC.updateNotificationsOnDensityOrFontScaleChanged()")
146         mPipeline?.allNotifs?.forEach { entry ->
147             entry.onDensityOrFontScaleChanged()
148             val exposedGuts = entry.areGutsExposed()
149             if (exposedGuts) {
150                 mGutsManager.onDensityOrFontScaleChanged(entry)
151             }
152         }
153     }
154 
155     private inline fun log(message: () -> String) {
156         if (DEBUG) Log.d(TAG, message())
157     }
158 
159     companion object {
160         private const val TAG = "ViewConfigCoordinator"
161         private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG)
162     }
163 }
164