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