1 /* 2 * Copyright (C) 2022 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 package com.android.systemui.statusbar.notification.collection.coordinator 17 18 import android.testing.TestableLooper.RunWithLooper 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SmallTest 21 import com.android.keyguard.KeyguardUpdateMonitor 22 import com.android.keyguard.KeyguardUpdateMonitorCallback 23 import com.android.systemui.SysuiTestCase 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.NotificationEntry 29 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow 30 import com.android.systemui.statusbar.notification.row.NotificationGutsManager 31 import com.android.systemui.statusbar.policy.ConfigurationController 32 import com.android.systemui.util.mockito.mock 33 import com.android.systemui.util.mockito.withArgCaptor 34 import org.junit.Before 35 import org.junit.Test 36 import org.junit.runner.RunWith 37 import org.mockito.Mockito.clearInvocations 38 import org.mockito.Mockito.verify 39 import org.mockito.Mockito.verifyNoMoreInteractions 40 import org.mockito.Mockito.`when` as whenever 41 42 @SmallTest 43 @RunWith(AndroidJUnit4::class) 44 @RunWithLooper 45 class ViewConfigCoordinatorTest : SysuiTestCase() { 46 private lateinit var coordinator: ViewConfigCoordinator 47 48 // Captured 49 private lateinit var userChangedListener: UserChangedListener 50 private lateinit var configurationListener: ConfigurationController.ConfigurationListener 51 private lateinit var keyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback 52 53 // Mocks 54 private val entry: NotificationEntry = mock() 55 private val row: ExpandableNotificationRow = mock() 56 private val pipeline: NotifPipeline = mock() 57 private val configurationController: ConfigurationController = mock() 58 private val lockscreenUserManager: NotificationLockscreenUserManager = mock() 59 private val gutsManager: NotificationGutsManager = mock() 60 private val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock() 61 private val colorUpdateLogger: ColorUpdateLogger = mock() 62 63 @Before setUpnull64 fun setUp() { 65 whenever(pipeline.allNotifs).thenReturn(listOf(entry)) 66 whenever(entry.row).thenReturn(row) 67 coordinator = ViewConfigCoordinator( 68 configurationController, 69 lockscreenUserManager, 70 gutsManager, 71 keyguardUpdateMonitor, 72 colorUpdateLogger, 73 ) 74 coordinator.attach(pipeline) 75 userChangedListener = withArgCaptor { 76 verify(lockscreenUserManager).addUserChangedListener(capture()) 77 } 78 configurationListener = withArgCaptor { 79 verify(configurationController).addCallback(capture()) 80 } 81 keyguardUpdateMonitorCallback = withArgCaptor { 82 verify(keyguardUpdateMonitor).registerCallback(capture()) 83 } 84 } 85 86 @Test uiModeChangePropagatesToRownull87 fun uiModeChangePropagatesToRow() { 88 configurationListener.onUiModeChanged() 89 verify(entry).row 90 verify(row).onUiModeChanged() 91 verifyNoMoreInteractions(entry, row) 92 } 93 94 @Test themeChangePropagatesToEntrynull95 fun themeChangePropagatesToEntry() { 96 configurationListener.onThemeChanged() 97 verify(entry).onDensityOrFontScaleChanged() 98 verify(entry).areGutsExposed() 99 verifyNoMoreInteractions(entry, row) 100 } 101 102 @Test densityChangePropagatesToEntrynull103 fun densityChangePropagatesToEntry() { 104 configurationListener.onDensityOrFontScaleChanged() 105 verify(entry).onDensityOrFontScaleChanged() 106 verify(entry).areGutsExposed() 107 verifyNoMoreInteractions(entry, row) 108 } 109 110 @Test switchingUserDefersChangesWithUserChangedEventAfternull111 fun switchingUserDefersChangesWithUserChangedEventAfter() { 112 // GIVEN switching users 113 keyguardUpdateMonitorCallback.onUserSwitching(10) 114 115 // WHEN configuration changes happen 116 configurationListener.onUiModeChanged() 117 configurationListener.onDensityOrFontScaleChanged() 118 configurationListener.onThemeChanged() 119 120 // VERIFY no changes are propagated 121 verifyNoMoreInteractions(entry, row) 122 123 // WHEN user switch completes 124 keyguardUpdateMonitorCallback.onUserSwitchComplete(10) 125 126 // VERIFY the changes propagate 127 verify(entry).row 128 verify(row).onUiModeChanged() 129 verify(entry).onDensityOrFontScaleChanged() 130 verify(entry).areGutsExposed() 131 verifyNoMoreInteractions(entry, row) 132 clearInvocations(entry, row) 133 134 // WHEN user change happens after the switching window 135 userChangedListener.onUserChanged(10) 136 137 // VERIFY user change itself does not re-trigger updates 138 verifyNoMoreInteractions(entry, row) 139 } 140 141 @Test switchingUserDefersChangesWithUserChangedEventDuringnull142 fun switchingUserDefersChangesWithUserChangedEventDuring() { 143 // GIVEN switching users 144 keyguardUpdateMonitorCallback.onUserSwitching(10) 145 146 // WHEN configuration changes happen 147 configurationListener.onUiModeChanged() 148 configurationListener.onDensityOrFontScaleChanged() 149 configurationListener.onThemeChanged() 150 151 // VERIFY no changes are propagated 152 verifyNoMoreInteractions(entry, row) 153 154 // WHEN user change happens during the switching window 155 userChangedListener.onUserChanged(10) 156 157 // VERIFY the changes propagate 158 verify(entry).row 159 verify(row).onUiModeChanged() 160 verify(entry).onDensityOrFontScaleChanged() 161 verify(entry).areGutsExposed() 162 verifyNoMoreInteractions(entry, row) 163 clearInvocations(entry, row) 164 165 // WHEN user switch completes 166 keyguardUpdateMonitorCallback.onUserSwitchComplete(10) 167 168 // VERIFY the switching window closing does not re-propagate 169 verifyNoMoreInteractions(entry, row) 170 } 171 172 @Test switchingUserDefersChangesWithUserChangedEventBeforenull173 fun switchingUserDefersChangesWithUserChangedEventBefore() { 174 // WHEN user change happens before configuration changes or switching window 175 userChangedListener.onUserChanged(10) 176 177 // VERIFY no changes happen 178 verifyNoMoreInteractions(entry, row) 179 180 // WHEN switching users then configuration changes happen 181 keyguardUpdateMonitorCallback.onUserSwitching(10) 182 183 configurationListener.onUiModeChanged() 184 configurationListener.onDensityOrFontScaleChanged() 185 configurationListener.onThemeChanged() 186 187 // VERIFY no changes happen 188 verifyNoMoreInteractions(entry, row) 189 190 // WHEN user switch completes 191 keyguardUpdateMonitorCallback.onUserSwitchComplete(10) 192 193 // VERIFY the changes propagate 194 verify(entry).row 195 verify(row).onUiModeChanged() 196 verify(entry).onDensityOrFontScaleChanged() 197 verify(entry).areGutsExposed() 198 verifyNoMoreInteractions(entry, row) 199 clearInvocations(entry, row) 200 } 201 } 202