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.notetask
17 
18 import android.app.role.RoleManager
19 import android.app.role.RoleManager.ROLE_NOTES
20 import android.os.UserHandle
21 import android.os.UserManager
22 import android.view.KeyEvent
23 import android.view.KeyEvent.ACTION_DOWN
24 import android.view.KeyEvent.ACTION_UP
25 import android.view.KeyEvent.KEYCODE_N
26 import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL
27 import androidx.test.ext.junit.runners.AndroidJUnit4
28 import androidx.test.filters.SmallTest
29 import com.android.keyguard.KeyguardUpdateMonitor
30 import com.android.systemui.SysuiTestCase
31 import com.android.systemui.settings.FakeUserTracker
32 import com.android.systemui.statusbar.CommandQueue
33 import com.android.systemui.util.concurrency.FakeExecutor
34 import com.android.systemui.util.mockito.any
35 import com.android.systemui.util.mockito.eq
36 import com.android.systemui.util.mockito.mock
37 import com.android.systemui.util.mockito.whenever
38 import com.android.systemui.util.mockito.withArgCaptor
39 import com.android.systemui.util.time.FakeSystemClock
40 import com.android.wm.shell.bubbles.Bubbles
41 import com.google.common.truth.Truth.assertThat
42 import java.util.Optional
43 import kotlinx.coroutines.ExperimentalCoroutinesApi
44 import org.junit.Before
45 import org.junit.Test
46 import org.junit.runner.RunWith
47 import org.mockito.Mock
48 import org.mockito.Mockito.never
49 import org.mockito.Mockito.times
50 import org.mockito.Mockito.verify
51 import org.mockito.Mockito.verifyZeroInteractions
52 import org.mockito.MockitoAnnotations.initMocks
53 
54 /** atest SystemUITests:NoteTaskInitializerTest */
55 @OptIn(ExperimentalCoroutinesApi::class, InternalNoteTaskApi::class)
56 @SmallTest
57 @RunWith(AndroidJUnit4::class)
58 internal class NoteTaskInitializerTest : SysuiTestCase() {
59 
60     @Mock lateinit var commandQueue: CommandQueue
61     @Mock lateinit var bubbles: Bubbles
62     @Mock lateinit var controller: NoteTaskController
63     @Mock lateinit var roleManager: RoleManager
64     @Mock lateinit var userManager: UserManager
65     @Mock lateinit var keyguardMonitor: KeyguardUpdateMonitor
66 
67     private val executor = FakeExecutor(FakeSystemClock())
68     private val userTracker = FakeUserTracker()
69     private val handlerCallbacks = mutableListOf<Runnable>()
70 
71     @Before
setUpnull72     fun setUp() {
73         initMocks(this)
74         whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
75     }
76 
createUnderTestnull77     private fun createUnderTest(
78         isEnabled: Boolean,
79         bubbles: Bubbles?,
80     ): NoteTaskInitializer =
81         NoteTaskInitializer(
82             controller = controller,
83             commandQueue = commandQueue,
84             optionalBubbles = Optional.ofNullable(bubbles),
85             isEnabled = isEnabled,
86             roleManager = roleManager,
87             userTracker = userTracker,
88             keyguardUpdateMonitor = keyguardMonitor,
89             backgroundExecutor = executor,
90         )
91 
92     private fun createKeyEvent(
93         action: Int,
94         code: Int,
95         downTime: Long = 0L,
96         eventTime: Long = 0L,
97         metaState: Int = 0
98     ): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState)
99 
100     @Test
101     fun initialize_withUserUnlocked() {
102         whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
103 
104         createUnderTest(isEnabled = true, bubbles = bubbles).initialize()
105 
106         verify(commandQueue).addCallback(any())
107         verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
108         verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
109         verify(keyguardMonitor).registerCallback(any())
110     }
111 
112     @Test
initialize_withUserLockednull113     fun initialize_withUserLocked() {
114         whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(false)
115 
116         createUnderTest(isEnabled = true, bubbles = bubbles).initialize()
117 
118         verify(commandQueue).addCallback(any())
119         verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
120         verify(controller, never()).setNoteTaskShortcutEnabled(any(), any())
121         verify(keyguardMonitor).registerCallback(any())
122         assertThat(userTracker.callbacks).isNotEmpty()
123     }
124 
125     @Test
initialize_flagDisablednull126     fun initialize_flagDisabled() {
127         val underTest = createUnderTest(isEnabled = false, bubbles = bubbles)
128 
129         underTest.initialize()
130 
131         verifyZeroInteractions(
132             commandQueue,
133             bubbles,
134             controller,
135             roleManager,
136             userManager,
137             keyguardMonitor,
138         )
139     }
140 
141     @Test
initialize_bubblesNotPresentnull142     fun initialize_bubblesNotPresent() {
143         val underTest = createUnderTest(isEnabled = true, bubbles = null)
144 
145         underTest.initialize()
146 
147         verifyZeroInteractions(
148             commandQueue,
149             bubbles,
150             controller,
151             roleManager,
152             userManager,
153             keyguardMonitor,
154         )
155     }
156 
157     @Test
initialize_handleSystemKeynull158     fun initialize_handleSystemKey() {
159         val expectedKeyEvent =
160             createKeyEvent(
161                 ACTION_DOWN,
162                 KEYCODE_N,
163                 metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
164             )
165         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
166         underTest.initialize()
167         val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
168 
169         callback.handleSystemKey(expectedKeyEvent)
170 
171         verify(controller).showNoteTask(any())
172     }
173 
174     @Test
initialize_userUnlocked_shouldUpdateNoteTasknull175     fun initialize_userUnlocked_shouldUpdateNoteTask() {
176         whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(false)
177         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
178         underTest.initialize()
179         val callback = withArgCaptor { verify(keyguardMonitor).registerCallback(capture()) }
180         whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
181 
182         callback.onUserUnlocked()
183 
184         verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
185     }
186 
187     @Test
initialize_onRoleHoldersChanged_shouldRunOnRoleHoldersChangednull188     fun initialize_onRoleHoldersChanged_shouldRunOnRoleHoldersChanged() {
189         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
190         underTest.initialize()
191         val callback = withArgCaptor {
192             verify(roleManager)
193                 .addOnRoleHoldersChangedListenerAsUser(any(), capture(), eq(UserHandle.ALL))
194         }
195 
196         callback.onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle)
197 
198         verify(controller).onRoleHoldersChanged(ROLE_NOTES, userTracker.userHandle)
199     }
200 
201     @Test
initialize_onProfilesChanged_shouldUpdateNoteTasknull202     fun initialize_onProfilesChanged_shouldUpdateNoteTask() {
203         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
204         underTest.initialize()
205 
206         userTracker.callbacks.first().onProfilesChanged(emptyList())
207 
208         verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
209     }
210 
211     @Test
initialize_onUserChanged_shouldUpdateNoteTasknull212     fun initialize_onUserChanged_shouldUpdateNoteTask() {
213         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
214         underTest.initialize()
215 
216         userTracker.callbacks.first().onUserChanged(0, mock())
217 
218         verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
219     }
220 
221     @Test
tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUpnull222     fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() {
223         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
224         underTest.initialize()
225         val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
226 
227         callback.handleSystemKey(
228             createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0)
229         )
230         verify(controller, never()).showNoteTask(any())
231 
232         callback.handleSystemKey(
233             createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50)
234         )
235 
236         verify(controller).showNoteTask(any())
237     }
238 
239     @Test
tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwicenull240     fun tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwice() {
241         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
242         underTest.initialize()
243         val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
244 
245         callback.handleSystemKey(
246             createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0)
247         )
248         callback.handleSystemKey(
249             createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50)
250         )
251         callback.handleSystemKey(
252             createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 99)
253         )
254         callback.handleSystemKey(
255             createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 150)
256         )
257 
258         verify(controller, times(1)).showNoteTask(any())
259     }
260 
261     @Test
tailButtonGestureDetection_longPress_shouldNotShowNoteTasknull262     fun tailButtonGestureDetection_longPress_shouldNotShowNoteTask() {
263         val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
264         underTest.initialize()
265         val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
266 
267         callback.handleSystemKey(
268             createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0)
269         )
270         callback.handleSystemKey(
271             createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 1000)
272         )
273 
274         verify(controller, never()).showNoteTask(any())
275     }
276 }
277