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