1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.statusbar;
16 
17 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
18 import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
19 import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
22 
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.Matchers.eq;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.verifyNoMoreInteractions;
28 
29 import android.content.ComponentName;
30 import android.graphics.Rect;
31 import android.hardware.biometrics.IBiometricSysuiReceiver;
32 import android.hardware.biometrics.PromptInfo;
33 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
34 import android.os.Bundle;
35 import android.view.KeyEvent;
36 import android.view.WindowInsets;
37 import android.view.WindowInsets.Type.InsetsType;
38 import android.view.WindowInsetsController.Appearance;
39 import android.view.WindowInsetsController.Behavior;
40 
41 import androidx.test.filters.SmallTest;
42 
43 import com.android.internal.statusbar.LetterboxDetails;
44 import com.android.internal.statusbar.StatusBarIcon;
45 import com.android.internal.view.AppearanceRegion;
46 import com.android.systemui.SysuiTestCase;
47 import com.android.systemui.settings.FakeDisplayTracker;
48 import com.android.systemui.statusbar.CommandQueue.Callbacks;
49 
50 import org.junit.After;
51 import org.junit.Before;
52 import org.junit.Test;
53 
54 @SmallTest
55 public class CommandQueueTest extends SysuiTestCase {
56 
57     private static final LetterboxDetails[] TEST_LETTERBOX_DETAILS = new LetterboxDetails[] {
58             new LetterboxDetails(
59                     /* letterboxInnerBounds= */ new Rect(100, 0, 200, 500),
60                     /* letterboxFullBounds= */ new Rect(0, 0, 500, 100),
61                     /* appAppearance= */ 123)
62     };
63 
64     private CommandQueue mCommandQueue;
65     private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
66     private Callbacks mCallbacks;
67     private static final int SECONDARY_DISPLAY = 1;
68 
69     @Before
setup()70     public void setup() {
71         mCommandQueue = new CommandQueue(mContext, mDisplayTracker);
72         mCallbacks = mock(Callbacks.class);
73         mCommandQueue.addCallback(mCallbacks);
74         verify(mCallbacks).disable(anyInt(), eq(0), eq(0), eq(false));
75     }
76 
77     @After
tearDown()78     public void tearDown() {
79         verifyNoMoreInteractions(mCallbacks);
80     }
81 
82     @Test
testIcon()83     public void testIcon() {
84         String slot = "testSlot";
85         StatusBarIcon icon = mock(StatusBarIcon.class);
86         mCommandQueue.setIcon(slot, icon);
87         waitForIdleSync();
88         verify(mCallbacks).setIcon(eq(slot), eq(icon));
89 
90         mCommandQueue.removeIcon(slot);
91         waitForIdleSync();
92         verify(mCallbacks).removeIcon(eq(slot));
93     }
94 
95     @Test
testDisable()96     public void testDisable() {
97         int state1 = 14;
98         int state2 = 42;
99         mCommandQueue.disable(DEFAULT_DISPLAY, state1, state2);
100         waitForIdleSync();
101         verify(mCallbacks).disable(eq(DEFAULT_DISPLAY), eq(state1), eq(state2), eq(true));
102     }
103 
104     @Test
testDisableForSecondaryDisplay()105     public void testDisableForSecondaryDisplay() {
106         int state1 = 14;
107         int state2 = 42;
108         mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2);
109         waitForIdleSync();
110         verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true));
111     }
112 
113     @Test
testExpandNotifications()114     public void testExpandNotifications() {
115         mCommandQueue.animateExpandNotificationsPanel();
116         waitForIdleSync();
117         verify(mCallbacks).animateExpandNotificationsPanel();
118     }
119 
120     @Test
testExpandSettings()121     public void testExpandSettings() {
122         String panel = "some_panel";
123         mCommandQueue.animateExpandSettingsPanel(panel);
124         waitForIdleSync();
125         verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
126     }
127 
128     @Test
testOnSystemBarAttributesChanged()129     public void testOnSystemBarAttributesChanged() {
130         doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1,
131                 new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
132                 BEHAVIOR_DEFAULT, WindowInsets.Type.defaultVisible(), "test",
133                 TEST_LETTERBOX_DETAILS);
134     }
135 
136     @Test
testOnSystemBarAttributesChangedForSecondaryDisplay()137     public void testOnSystemBarAttributesChangedForSecondaryDisplay() {
138         doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1,
139                 new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
140                 BEHAVIOR_DEFAULT, WindowInsets.Type.defaultVisible(), "test",
141                 TEST_LETTERBOX_DETAILS);
142     }
143 
doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)144     private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance,
145             AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
146             @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName,
147             LetterboxDetails[] letterboxDetails) {
148         mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
149                 navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
150                 letterboxDetails);
151         waitForIdleSync();
152         verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance),
153                 eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior),
154                 eq(requestedVisibleTypes), eq(packageName), eq(letterboxDetails));
155     }
156 
157     @Test
testShowTransient()158     public void testShowTransient() {
159         int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
160         mCommandQueue.showTransient(DEFAULT_DISPLAY, types, true /* isGestureOnSystemBar */);
161         waitForIdleSync();
162         verify(mCallbacks).showTransient(eq(DEFAULT_DISPLAY), eq(types), eq(true));
163     }
164 
165     @Test
testShowTransientForSecondaryDisplay()166     public void testShowTransientForSecondaryDisplay() {
167         int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
168         mCommandQueue.showTransient(SECONDARY_DISPLAY, types, true /* isGestureOnSystemBar */);
169         waitForIdleSync();
170         verify(mCallbacks).showTransient(eq(SECONDARY_DISPLAY), eq(types), eq(true));
171     }
172 
173     @Test
testAbortTransient()174     public void testAbortTransient() {
175         int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
176         mCommandQueue.abortTransient(DEFAULT_DISPLAY, types);
177         waitForIdleSync();
178         verify(mCallbacks).abortTransient(eq(DEFAULT_DISPLAY), eq(types));
179     }
180 
181     @Test
testAbortTransientForSecondaryDisplay()182     public void testAbortTransientForSecondaryDisplay() {
183         int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
184         mCommandQueue.abortTransient(SECONDARY_DISPLAY, types);
185         waitForIdleSync();
186         verify(mCallbacks).abortTransient(eq(SECONDARY_DISPLAY), eq(types));
187     }
188 
189     @Test
testShowImeButton()190     public void testShowImeButton() {
191         mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
192         waitForIdleSync();
193         verify(mCallbacks).setImeWindowStatus(
194                 eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true));
195     }
196 
197     @Test
testShowImeButtonForSecondaryDisplay()198     public void testShowImeButtonForSecondaryDisplay() {
199         // First show in default display to update the "last updated ime display"
200         testShowImeButton();
201 
202         mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
203         waitForIdleSync();
204         verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(IME_INVISIBLE),
205                 eq(BACK_DISPOSITION_DEFAULT), eq(false));
206         verify(mCallbacks).setImeWindowStatus(
207                 eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
208     }
209 
210     @Test
testShowRecentApps()211     public void testShowRecentApps() {
212         mCommandQueue.showRecentApps(true);
213         waitForIdleSync();
214         verify(mCallbacks).showRecentApps(eq(true));
215     }
216 
217     @Test
testHideRecentApps()218     public void testHideRecentApps() {
219         mCommandQueue.hideRecentApps(true, false);
220         waitForIdleSync();
221         verify(mCallbacks).hideRecentApps(eq(true), eq(false));
222     }
223 
224     @Test
testToggleRecentApps()225     public void testToggleRecentApps() {
226         mCommandQueue.toggleRecentApps();
227         waitForIdleSync();
228         verify(mCallbacks).toggleRecentApps();
229     }
230 
231     @Test
testPreloadRecentApps()232     public void testPreloadRecentApps() {
233         mCommandQueue.preloadRecentApps();
234         waitForIdleSync();
235         verify(mCallbacks).preloadRecentApps();
236     }
237 
238     @Test
testCancelPreloadRecentApps()239     public void testCancelPreloadRecentApps() {
240         mCommandQueue.cancelPreloadRecentApps();
241         waitForIdleSync();
242         verify(mCallbacks).cancelPreloadRecentApps();
243     }
244 
245     @Test
testDismissKeyboardShortcuts()246     public void testDismissKeyboardShortcuts() {
247         mCommandQueue.dismissKeyboardShortcutsMenu();
248         waitForIdleSync();
249         verify(mCallbacks).dismissKeyboardShortcutsMenu();
250     }
251 
252     @Test
testToggleKeyboardShortcuts()253     public void testToggleKeyboardShortcuts() {
254         mCommandQueue.toggleKeyboardShortcutsMenu(1);
255         waitForIdleSync();
256         verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
257     }
258 
259     @Test
testSetWindowState()260     public void testSetWindowState() {
261         mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
262         waitForIdleSync();
263         verify(mCallbacks).setWindowState(eq(DEFAULT_DISPLAY), eq(1), eq(2));
264     }
265 
266     @Test
testSetWindowStateForSecondaryDisplay()267     public void testSetWindowStateForSecondaryDisplay() {
268         mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2);
269         waitForIdleSync();
270         verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2));
271     }
272 
273     @Test
testScreenPinRequest()274     public void testScreenPinRequest() {
275         mCommandQueue.showScreenPinningRequest(1);
276         waitForIdleSync();
277         verify(mCallbacks).showScreenPinningRequest(eq(1));
278     }
279 
280     @Test
testAppTransitionPending()281     public void testAppTransitionPending() {
282         mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
283         waitForIdleSync();
284         verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
285     }
286 
287     @Test
testAppTransitionPendingForSecondaryDisplay()288     public void testAppTransitionPendingForSecondaryDisplay() {
289         mCommandQueue.appTransitionPending(SECONDARY_DISPLAY);
290         waitForIdleSync();
291         verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false));
292     }
293 
294     @Test
testAppTransitionCancelled()295     public void testAppTransitionCancelled() {
296         mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
297         waitForIdleSync();
298         verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
299     }
300 
301     @Test
testAppTransitionCancelledForSecondaryDisplay()302     public void testAppTransitionCancelledForSecondaryDisplay() {
303         mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY);
304         waitForIdleSync();
305         verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY));
306     }
307 
308     @Test
testAppTransitionStarting()309     public void testAppTransitionStarting() {
310         mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
311         waitForIdleSync();
312         verify(mCallbacks).appTransitionStarting(
313                 eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
314     }
315 
316     @Test
testAppTransitionStartingForSecondaryDisplay()317     public void testAppTransitionStartingForSecondaryDisplay() {
318         mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2);
319         waitForIdleSync();
320         verify(mCallbacks).appTransitionStarting(
321                 eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false));
322     }
323 
324     @Test
testAppTransitionFinished()325     public void testAppTransitionFinished() {
326         mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
327         waitForIdleSync();
328         verify(mCallbacks).appTransitionFinished(eq(DEFAULT_DISPLAY));
329     }
330 
331     @Test
testAppTransitionFinishedForSecondaryDisplay()332     public void testAppTransitionFinishedForSecondaryDisplay() {
333         mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY);
334         waitForIdleSync();
335         verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY));
336     }
337 
338     @Test
testAssistDisclosure()339     public void testAssistDisclosure() {
340         mCommandQueue.showAssistDisclosure();
341         waitForIdleSync();
342         verify(mCallbacks).showAssistDisclosure();
343     }
344 
345     @Test
testStartAssist()346     public void testStartAssist() {
347         Bundle b = new Bundle();
348         mCommandQueue.startAssist(b);
349         waitForIdleSync();
350         verify(mCallbacks).startAssist(eq(b));
351     }
352 
353     @Test
testCameraLaunchGesture()354     public void testCameraLaunchGesture() {
355         mCommandQueue.onCameraLaunchGestureDetected(1);
356         waitForIdleSync();
357         verify(mCallbacks).onCameraLaunchGestureDetected(eq(1));
358     }
359 
360     @Test
testShowPipMenu()361     public void testShowPipMenu() {
362         mCommandQueue.showPictureInPictureMenu();
363         waitForIdleSync();
364         verify(mCallbacks).showPictureInPictureMenu();
365     }
366 
367     @Test
testAddQsTile()368     public void testAddQsTile() {
369         ComponentName c = new ComponentName("testpkg", "testcls");
370         mCommandQueue.addQsTile(c);
371         waitForIdleSync();
372         verify(mCallbacks).addQsTile(eq(c));
373     }
374 
375     @Test
testRemoveQsTile()376     public void testRemoveQsTile() {
377         ComponentName c = new ComponentName("testpkg", "testcls");
378         mCommandQueue.remQsTile(c);
379         waitForIdleSync();
380         verify(mCallbacks).remQsTile(eq(c));
381     }
382 
383     @Test
testClickQsTile()384     public void testClickQsTile() {
385         ComponentName c = new ComponentName("testpkg", "testcls");
386         mCommandQueue.clickQsTile(c);
387         waitForIdleSync();
388         verify(mCallbacks).clickTile(eq(c));
389     }
390 
391     @Test
testToggleAppSplitScreen()392     public void testToggleAppSplitScreen() {
393         mCommandQueue.toggleSplitScreen();
394         waitForIdleSync();
395         verify(mCallbacks).toggleSplitScreen();
396     }
397 
398     @Test
testHandleSysKey()399     public void testHandleSysKey() {
400         KeyEvent testEvent = new KeyEvent(1, 1);
401         mCommandQueue.handleSystemKey(testEvent);
402         waitForIdleSync();
403         verify(mCallbacks).handleSystemKey(eq(testEvent));
404     }
405 
406     @Test
testOnDisplayReady()407     public void testOnDisplayReady() {
408         mCommandQueue.onDisplayReady(DEFAULT_DISPLAY);
409         waitForIdleSync();
410         verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY));
411     }
412 
413     @Test
testOnDisplayReadyForSecondaryDisplay()414     public void testOnDisplayReadyForSecondaryDisplay() {
415         mCommandQueue.onDisplayReady(SECONDARY_DISPLAY);
416         waitForIdleSync();
417         verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY));
418     }
419 
420     @Test
testOnDisplayRemoved()421     public void testOnDisplayRemoved() {
422         mDisplayTracker.triggerOnDisplayRemoved(SECONDARY_DISPLAY);
423         waitForIdleSync();
424         verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
425     }
426 
427     @Test
testOnRecentsAnimationStateChanged()428     public void testOnRecentsAnimationStateChanged() {
429         mCommandQueue.onRecentsAnimationStateChanged(true);
430         waitForIdleSync();
431         verify(mCallbacks).onRecentsAnimationStateChanged(eq(true));
432     }
433 
434     @Test
testShowAuthenticationDialog()435     public void testShowAuthenticationDialog() {
436         PromptInfo promptInfo = new PromptInfo();
437         final IBiometricSysuiReceiver receiver = mock(IBiometricSysuiReceiver.class);
438         final int[] sensorIds = {1, 2};
439         final boolean credentialAllowed = true;
440         final boolean requireConfirmation = true;
441         final int userId = 10;
442         final long operationId = 1;
443         final String packageName = "test";
444         final long requestId = 10;
445 
446         mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
447                 credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId);
448         waitForIdleSync();
449         verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
450                 eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId),
451                 eq(packageName), eq(requestId));
452     }
453 
454     @Test
testOnBiometricAuthenticated()455     public void testOnBiometricAuthenticated() {
456         final int id = 12;
457         mCommandQueue.onBiometricAuthenticated(id);
458         waitForIdleSync();
459         verify(mCallbacks).onBiometricAuthenticated(eq(id));
460     }
461 
462     @Test
testOnBiometricHelp()463     public void testOnBiometricHelp() {
464         final int modality = TYPE_FACE;
465         final String helpMessage = "test_help_message";
466         mCommandQueue.onBiometricHelp(modality, helpMessage);
467         waitForIdleSync();
468         verify(mCallbacks).onBiometricHelp(eq(modality), eq(helpMessage));
469     }
470 
471     @Test
testOnBiometricError()472     public void testOnBiometricError() {
473         final int modality = 1;
474         final int error = 2;
475         final int vendorCode = 3;
476         mCommandQueue.onBiometricError(modality, error, vendorCode);
477         waitForIdleSync();
478         verify(mCallbacks).onBiometricError(eq(modality), eq(error), eq(vendorCode));
479     }
480 
481     @Test
testHideAuthenticationDialog()482     public void testHideAuthenticationDialog() {
483         final long id = 4;
484         mCommandQueue.hideAuthenticationDialog(id);
485         waitForIdleSync();
486         verify(mCallbacks).hideAuthenticationDialog(eq(id));
487     }
488 
489     @Test
testSetUdfpsRefreshRateCallback()490     public void testSetUdfpsRefreshRateCallback() {
491         final IUdfpsRefreshRateRequestCallback callback =
492                 mock(IUdfpsRefreshRateRequestCallback.class);
493         mCommandQueue.setUdfpsRefreshRateCallback(callback);
494         waitForIdleSync();
495         verify(mCallbacks).setUdfpsRefreshRateCallback(eq(callback));
496     }
497 
498     @Test
testSuppressAmbientDisplay()499     public void testSuppressAmbientDisplay() {
500         mCommandQueue.suppressAmbientDisplay(true);
501         waitForIdleSync();
502         verify(mCallbacks).suppressAmbientDisplay(true);
503     }
504 
505     @Test
testRequestWindowMagnificationConnection()506     public void testRequestWindowMagnificationConnection() {
507         mCommandQueue.requestWindowMagnificationConnection(true);
508         waitForIdleSync();
509         verify(mCallbacks).requestWindowMagnificationConnection(true);
510     }
511 
512     @Test
testSetEnableNavigationBarLumaSampling()513     public void testSetEnableNavigationBarLumaSampling() {
514         mCommandQueue.setNavigationBarLumaSamplingEnabled(1, true);
515         waitForIdleSync();
516         verify(mCallbacks).setNavigationBarLumaSamplingEnabled(eq(1), eq(true));
517     }
518 
519     @Test
testConfirmImmersivePrompt()520     public void testConfirmImmersivePrompt() {
521         mCommandQueue.confirmImmersivePrompt();
522         waitForIdleSync();
523         verify(mCallbacks).confirmImmersivePrompt();
524     }
525 
526     @Test
testImmersiveModeChanged()527     public void testImmersiveModeChanged() {
528         final int displayAreaId = 10;
529         mCommandQueue.immersiveModeChanged(displayAreaId, true);
530         waitForIdleSync();
531         verify(mCallbacks).immersiveModeChanged(displayAreaId, true);
532     }
533 
534     @Test
testShowRearDisplayDialog()535     public void testShowRearDisplayDialog() {
536         final int currentBaseState = 1;
537         mCommandQueue.showRearDisplayDialog(currentBaseState);
538         waitForIdleSync();
539         verify(mCallbacks).showRearDisplayDialog(eq(currentBaseState));
540     }
541 }
542