1 /*
2  * Copyright (C) 2016 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 android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
21 import static android.server.wm.CliIntentExtra.extraString;
22 import static android.server.wm.MockImeHelper.createManagedMockImeSession;
23 import static android.server.wm.UiDeviceUtils.pressBackButton;
24 import static android.server.wm.app.Components.DISMISS_KEYGUARD_ACTIVITY;
25 import static android.server.wm.app.Components.DISMISS_KEYGUARD_METHOD_ACTIVITY;
26 import static android.server.wm.app.Components.PIP_ACTIVITY;
27 import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP;
28 import static android.server.wm.app.Components.PipActivity.EXTRA_DISMISS_KEYGUARD;
29 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
30 import static android.server.wm.app.Components.PipActivity.EXTRA_SHOW_OVER_KEYGUARD;
31 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ACTIVITY;
32 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ATTR_IME_ACTIVITY;
33 import static android.server.wm.app.Components.TURN_SCREEN_ON_ACTIVITY;
34 import static android.server.wm.app.Components.TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY;
35 import static android.view.Display.DEFAULT_DISPLAY;
36 import static android.view.WindowInsets.Type.ime;
37 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
38 
39 import static androidx.test.InstrumentationRegistry.getInstrumentation;
40 
41 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
42 
43 import static org.junit.Assert.assertFalse;
44 import static org.junit.Assert.assertTrue;
45 import static org.junit.Assume.assumeFalse;
46 import static org.junit.Assume.assumeTrue;
47 
48 import android.app.Activity;
49 import android.app.KeyguardManager;
50 import android.content.ComponentName;
51 import android.os.Bundle;
52 import android.os.SystemClock;
53 import android.platform.test.annotations.Presubmit;
54 import android.server.wm.app.Components;
55 import android.view.View;
56 import android.widget.EditText;
57 import android.widget.LinearLayout;
58 
59 import com.android.compatibility.common.util.CtsTouchUtils;
60 import com.android.compatibility.common.util.PollingCheck;
61 import com.android.cts.mockime.ImeEventStream;
62 import com.android.cts.mockime.MockImeSession;
63 
64 import org.junit.Before;
65 import org.junit.Test;
66 
67 import java.util.concurrent.TimeUnit;
68 
69 /**
70  * Build/Install/Run:
71  *     atest CtsWindowManagerDeviceTestCases:KeyguardLockedTests
72  */
73 @Presubmit
74 @android.server.wm.annotation.Group2
75 public class KeyguardLockedTests extends KeyguardTestBase {
76 
77     private final static long TIMEOUT_IME = TimeUnit.SECONDS.toMillis(5);
78 
79     @Before
80     @Override
setUp()81     public void setUp() throws Exception {
82         super.setUp();
83         assumeTrue(supportsSecureLock());
84     }
85 
86     @Test
testLockAndUnlock()87     public void testLockAndUnlock() {
88         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
89         lockScreenSession.setLockCredential().gotoKeyguard();
90 
91         assertTrue(mKeyguardManager.isKeyguardLocked());
92         assertTrue(mKeyguardManager.isDeviceLocked());
93         assertTrue(mKeyguardManager.isDeviceSecure());
94         assertTrue(mKeyguardManager.isKeyguardSecure());
95         mWmState.assertKeyguardShowingAndNotOccluded();
96 
97         lockScreenSession.unlockDevice().enterAndConfirmLockCredential();
98 
99         mWmState.waitAndAssertKeyguardGone();
100         assertFalse(mKeyguardManager.isDeviceLocked());
101         assertFalse(mKeyguardManager.isKeyguardLocked());
102     }
103 
104     @Test
testDisableKeyguard_thenSettingCredential_reenablesKeyguard_b119322269()105     public void testDisableKeyguard_thenSettingCredential_reenablesKeyguard_b119322269() {
106         final KeyguardManager.KeyguardLock keyguardLock = mContext.getSystemService(
107                 KeyguardManager.class).newKeyguardLock("KeyguardLockedTests");
108 
109         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
110             lockScreenSession.gotoKeyguard();
111             keyguardLock.disableKeyguard();
112 
113             lockScreenSession.setLockCredential();
114             lockScreenSession.gotoKeyguard();
115 
116             mWmState.waitForKeyguardShowingAndNotOccluded();
117             mWmState.assertKeyguardShowingAndNotOccluded();
118             assertTrue(mKeyguardManager.isKeyguardLocked());
119             assertTrue(mKeyguardManager.isDeviceLocked());
120             assertTrue(mKeyguardManager.isDeviceSecure());
121             assertTrue(mKeyguardManager.isKeyguardSecure());
122         } finally {
123             keyguardLock.reenableKeyguard();
124         }
125     }
126 
127     @Test
testDismissKeyguard()128     public void testDismissKeyguard() {
129         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
130         lockScreenSession.setLockCredential().gotoKeyguard();
131 
132         mWmState.assertKeyguardShowingAndNotOccluded();
133         launchActivity(DISMISS_KEYGUARD_ACTIVITY);
134         lockScreenSession.enterAndConfirmLockCredential();
135 
136         mWmState.waitAndAssertKeyguardGone();
137         mWmState.assertVisibility(DISMISS_KEYGUARD_ACTIVITY, true);
138     }
139 
140     @Test
testDismissKeyguard_whileOccluded()141     public void testDismissKeyguard_whileOccluded() {
142         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
143         lockScreenSession.setLockCredential().gotoKeyguard();
144 
145         mWmState.assertKeyguardShowingAndNotOccluded();
146         launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
147         mWmState.computeState(SHOW_WHEN_LOCKED_ACTIVITY);
148         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
149 
150         launchActivity(DISMISS_KEYGUARD_ACTIVITY);
151         lockScreenSession.enterAndConfirmLockCredential();
152         mWmState.waitAndAssertKeyguardGone();
153         mWmState.computeState(DISMISS_KEYGUARD_ACTIVITY);
154 
155         final boolean isDismissTranslucent = mWmState
156                 .isActivityTranslucent(DISMISS_KEYGUARD_ACTIVITY);
157         mWmState.assertVisibility(DISMISS_KEYGUARD_ACTIVITY, true);
158         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, isDismissTranslucent);
159     }
160 
161     @Test
testDismissKeyguard_fromShowWhenLocked_notAllowed()162     public void testDismissKeyguard_fromShowWhenLocked_notAllowed() {
163         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
164         lockScreenSession.setLockCredential().gotoKeyguard();
165 
166         mWmState.assertKeyguardShowingAndNotOccluded();
167         launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
168         mWmState.computeState(SHOW_WHEN_LOCKED_ACTIVITY);
169         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
170         mBroadcastActionTrigger.dismissKeyguardByFlag();
171         lockScreenSession.enterAndConfirmLockCredential();
172 
173         // Make sure we stay on Keyguard.
174         mWmState.assertKeyguardShowingAndOccluded();
175         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
176     }
177 
178     @Test
testDismissKeyguardActivity_method()179     public void testDismissKeyguardActivity_method() {
180         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
181         lockScreenSession.setLockCredential();
182         separateTestJournal();
183 
184         lockScreenSession.gotoKeyguard();
185         mWmState.computeState();
186         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
187 
188         launchActivity(DISMISS_KEYGUARD_METHOD_ACTIVITY);
189         lockScreenSession.enterAndConfirmLockCredential();
190         mWmState.waitForKeyguardGone();
191         mWmState.computeState(DISMISS_KEYGUARD_METHOD_ACTIVITY);
192         mWmState.assertVisibility(DISMISS_KEYGUARD_METHOD_ACTIVITY, true);
193         assertFalse(mWmState.getKeyguardControllerState().keyguardShowing);
194         assertOnDismissSucceeded(DISMISS_KEYGUARD_METHOD_ACTIVITY);
195     }
196 
197     @Test
testDismissKeyguardActivity_method_cancelled()198     public void testDismissKeyguardActivity_method_cancelled() {
199         // Pressing the back button does not cancel Keyguard in AAOS.
200         assumeFalse(isCar());
201 
202         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
203         lockScreenSession.setLockCredential();
204         separateTestJournal();
205 
206         lockScreenSession.gotoKeyguard();
207         mWmState.computeState();
208         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
209 
210         launchActivity(DISMISS_KEYGUARD_METHOD_ACTIVITY);
211         pressBackButton();
212         assertOnDismissCancelled(DISMISS_KEYGUARD_METHOD_ACTIVITY);
213         mWmState.computeState();
214         mWmState.assertVisibility(DISMISS_KEYGUARD_METHOD_ACTIVITY, false);
215         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
216     }
217 
218     @Test
testDismissKeyguardAttrActivity_method_turnScreenOn_withSecureKeyguard()219     public void testDismissKeyguardAttrActivity_method_turnScreenOn_withSecureKeyguard() {
220         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
221         lockScreenSession.setLockCredential().sleepDevice();
222         mWmState.computeState();
223         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
224 
225         launchActivity(TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY);
226         mWmState.waitForKeyguardShowingAndNotOccluded();
227         mWmState.assertVisibility(TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY, false);
228         assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
229         assertTrue(isDisplayOn(DEFAULT_DISPLAY));
230     }
231 
232     @Test
testEnterPipOverKeyguard()233     public void testEnterPipOverKeyguard() {
234         assumeTrue(supportsPip());
235 
236         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
237         lockScreenSession.setLockCredential();
238 
239         // Show the PiP activity in fullscreen.
240         launchActivity(PIP_ACTIVITY, extraString(EXTRA_SHOW_OVER_KEYGUARD, "true"));
241 
242         // Lock the screen and ensure that the PiP activity showing over the LockScreen.
243         lockScreenSession.gotoKeyguard(PIP_ACTIVITY);
244         mWmState.waitForKeyguardShowingAndOccluded();
245         mWmState.assertKeyguardShowingAndOccluded();
246 
247         // Request that the PiP activity enter picture-in-picture mode (ensure it does not).
248         mBroadcastActionTrigger.doAction(ACTION_ENTER_PIP);
249         waitForEnterPip(PIP_ACTIVITY);
250         mWmState.assertDoesNotContainStack("Must not contain pinned stack.",
251                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
252 
253         // Enter the credentials and ensure that the activity actually entered picture-in-picture.
254         lockScreenSession.enterAndConfirmLockCredential();
255         mWmState.waitAndAssertKeyguardGone();
256         waitForEnterPip(PIP_ACTIVITY);
257         mWmState.assertContainsStack("Must contain pinned stack.", WINDOWING_MODE_PINNED,
258                 ACTIVITY_TYPE_STANDARD);
259     }
260 
261     @Test
testShowWhenLockedActivityAndPipActivity()262     public void testShowWhenLockedActivityAndPipActivity() {
263         assumeTrue(supportsPip());
264 
265         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
266         lockScreenSession.setLockCredential();
267 
268         // Show an activity in PIP.
269         launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true"));
270         waitForEnterPip(PIP_ACTIVITY);
271         mWmState.assertContainsStack("Must contain pinned stack.", WINDOWING_MODE_PINNED,
272                 ACTIVITY_TYPE_STANDARD);
273         mWmState.assertVisibility(PIP_ACTIVITY, true);
274 
275         // Show an activity that will keep above the keyguard.
276         launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
277         mWmState.computeState(SHOW_WHEN_LOCKED_ACTIVITY);
278         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
279 
280         // Lock the screen and ensure that the fullscreen activity showing over the lockscreen
281         // is visible, but not the PiP activity.
282         lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_ACTIVITY);
283         mWmState.computeState();
284         mWmState.assertKeyguardShowingAndOccluded();
285         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
286         mWmState.assertVisibility(PIP_ACTIVITY, false);
287     }
288 
289     @Test
testShowWhenLockedPipActivity()290     public void testShowWhenLockedPipActivity() {
291         assumeTrue(supportsPip());
292 
293         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
294         lockScreenSession.setLockCredential();
295 
296         // Show an activity in PIP.
297         launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true"),
298                 extraString(EXTRA_SHOW_OVER_KEYGUARD, "true"));
299         waitForEnterPip(PIP_ACTIVITY);
300         mWmState.assertContainsStack("Must contain pinned stack.", WINDOWING_MODE_PINNED,
301                 ACTIVITY_TYPE_STANDARD);
302         mWmState.assertVisibility(PIP_ACTIVITY, true);
303 
304         // Lock the screen and ensure the PiP activity is not visible on the lockscreen even
305         // though it's marked as showing over the lockscreen itself.
306         lockScreenSession.gotoKeyguard();
307         mWmState.assertKeyguardShowingAndNotOccluded();
308         mWmState.assertVisibility(PIP_ACTIVITY, false);
309     }
310 
311     @Test
testDismissKeyguardPipActivity()312     public void testDismissKeyguardPipActivity() {
313         assumeTrue(supportsPip());
314 
315         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
316         // Show an activity in PIP.
317         launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true"),
318                 extraString(EXTRA_DISMISS_KEYGUARD, "true"));
319         waitForEnterPip(PIP_ACTIVITY);
320         mWmState.assertContainsStack("Must contain pinned stack.", WINDOWING_MODE_PINNED,
321                 ACTIVITY_TYPE_STANDARD);
322         mWmState.assertVisibility(PIP_ACTIVITY, true);
323 
324         // Lock the screen and ensure the PiP activity is not visible on the lockscreen even
325         // though it's marked as dismiss keyguard.
326         lockScreenSession.gotoKeyguard();
327         mWmState.computeState();
328         mWmState.assertKeyguardShowingAndNotOccluded();
329         mWmState.assertVisibility(PIP_ACTIVITY, false);
330     }
331 
332     @Test
testShowWhenLockedAttrImeActivityAndShowSoftInput()333     public void testShowWhenLockedAttrImeActivityAndShowSoftInput() throws Exception {
334         assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
335 
336         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
337         final MockImeSession mockImeSession = createManagedMockImeSession(this);
338 
339         lockScreenSession.setLockCredential().gotoKeyguard();
340         mWmState.assertKeyguardShowingAndNotOccluded();
341         launchActivity(SHOW_WHEN_LOCKED_ATTR_IME_ACTIVITY);
342         mWmState.computeState(SHOW_WHEN_LOCKED_ATTR_IME_ACTIVITY);
343         mWmState.assertVisibility(SHOW_WHEN_LOCKED_ATTR_IME_ACTIVITY, true);
344 
345         // Make sure the activity has been called showSoftInput & IME window is visible.
346         final ImeEventStream stream = mockImeSession.openEventStream();
347         expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
348                 TIMEOUT_IME);
349         // Assert the IME is shown on the expected display.
350         mWmState.waitAndAssertImeWindowShownOnDisplay(DEFAULT_DISPLAY);
351     }
352 
353     @Test
testShowWhenLockedImeActivityAndShowSoftInput()354     public void testShowWhenLockedImeActivityAndShowSoftInput() throws Exception {
355         assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
356 
357         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
358         final MockImeSession mockImeSession = createManagedMockImeSession(this);
359         final TestActivitySession<ShowWhenLockedImeActivity> imeTestActivitySession =
360                 createManagedTestActivitySession();
361 
362         lockScreenSession.setLockCredential().gotoKeyguard();
363         mWmState.assertKeyguardShowingAndNotOccluded();
364         imeTestActivitySession.launchTestActivityOnDisplaySync(ShowWhenLockedImeActivity.class,
365                 DEFAULT_DISPLAY);
366 
367         // Make sure the activity has been called showSoftInput & IME window is visible.
368         final ImeEventStream stream = mockImeSession.openEventStream();
369         expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
370                 TIMEOUT_IME);
371         // Assert the IME is shown on the expected display.
372         mWmState.waitAndAssertImeWindowShownOnDisplay(DEFAULT_DISPLAY);
373 
374     }
375 
376     @Test
testImeShowsAfterLockScreenOnEditorTap()377     public void testImeShowsAfterLockScreenOnEditorTap() throws Exception {
378         assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
379 
380         final MockImeSession mockImeSession = createManagedMockImeSession(this);
381         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
382         final TestActivitySession<ShowImeAfterLockscreenActivity> imeTestActivitySession =
383                 createManagedTestActivitySession();
384         imeTestActivitySession.launchTestActivityOnDisplaySync(ShowImeAfterLockscreenActivity.class,
385                 DEFAULT_DISPLAY);
386 
387         final ShowImeAfterLockscreenActivity activity = imeTestActivitySession.getActivity();
388         final View rootView = activity.getWindow().getDecorView();
389 
390         CtsTouchUtils.emulateTapOnViewCenter(getInstrumentation(), null, activity.mEditor);
391         PollingCheck.waitFor(
392                 TIMEOUT_IME,
393                 () -> rootView.getRootWindowInsets().isVisible(ime()));
394 
395         lockScreenSession.setLockCredential().gotoKeyguard();
396         assertTrue("Keyguard is showing", mWmState.getKeyguardControllerState().keyguardShowing);
397         lockScreenSession.enterAndConfirmLockCredential();
398         mWmState.waitAndAssertKeyguardGone();
399 
400         final ImeEventStream stream = mockImeSession.openEventStream();
401 
402         CtsTouchUtils.emulateTapOnViewCenter(getInstrumentation(), null, activity.mEditor);
403 
404         // Make sure the activity has been called showSoftInput & IME window is visible.
405         expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
406                 TimeUnit.SECONDS.toMillis(5) /* eventTimeout */);
407         // Assert the IME is shown event on the expected display.
408         mWmState.waitAndAssertImeWindowShownOnDisplay(DEFAULT_DISPLAY);
409         // Check if IME is actually visible.
410         PollingCheck.waitFor(
411                 TIMEOUT_IME,
412                 () -> rootView.getRootWindowInsets().isVisible(ime()));
413     }
414 
415     public static class ShowImeAfterLockscreenActivity extends Activity {
416 
417         EditText mEditor;
418 
419         @Override
onCreate(Bundle icicle)420         protected void onCreate(Bundle icicle) {
421             super.onCreate(icicle);
422             mEditor = createViews(this, false /* showWhenLocked */);
423         }
424     }
425 
426     public static class ShowWhenLockedImeActivity extends Activity {
427 
428         @Override
onCreate(Bundle icicle)429         protected void onCreate(Bundle icicle) {
430             super.onCreate(icicle);
431             createViews(this, true /* showWhenLocked */);
432         }
433     }
434 
createViews( Activity activity, boolean showWhenLocked )435     private static EditText createViews(
436             Activity activity, boolean showWhenLocked /* showWhenLocked */) {
437         EditText editor = new EditText(activity);
438         // Set private IME option for editorMatcher to identify which TextView received
439         // onStartInput event.
440         editor.setPrivateImeOptions(
441                 activity.getClass().getName()
442                         + "/" + Long.toString(SystemClock.elapsedRealtimeNanos()));
443         final LinearLayout layout = new LinearLayout(activity);
444         layout.setOrientation(LinearLayout.VERTICAL);
445         layout.addView(editor);
446         activity.setContentView(layout);
447 
448         if (showWhenLocked) {
449             // Set showWhenLocked as true & request focus for showing soft input.
450             activity.setShowWhenLocked(true);
451             activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
452         }
453         editor.requestFocus();
454         return editor;
455     }
456 
457     /**
458      * Waits until the given activity has entered picture-in-picture mode (allowing for the
459      * subsequent animation to start).
460      */
waitForEnterPip(ComponentName activityName)461     private void waitForEnterPip(ComponentName activityName) {
462         mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
463                 .setWindowingMode(WINDOWING_MODE_PINNED)
464                 .setActivityType(ACTIVITY_TYPE_STANDARD)
465                 .build());
466     }
467 }
468