• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.system.helpers;
18 
19 import android.app.KeyguardManager;
20 import android.content.Context;
21 import android.graphics.Point;
22 import android.provider.Settings;
23 import android.support.test.InstrumentationRegistry;
24 import android.support.test.uiautomator.By;
25 import android.support.test.uiautomator.BySelector;
26 import android.support.test.uiautomator.UiDevice;
27 import android.support.test.uiautomator.UiObject2;
28 import android.support.test.uiautomator.Until;
29 import android.system.helpers.ActivityHelper;
30 import android.system.helpers.DeviceHelper;
31 
32 import junit.framework.Assert;
33 
34 import java.io.IOException;
35 import java.util.regex.Pattern;
36 
37 /**
38  * Implement common helper methods for Lockscreen.
39  */
40 public class LockscreenHelper {
41     private static final String LOG_TAG = LockscreenHelper.class.getSimpleName();
42     public static final int SHORT_TIMEOUT = 200;
43     public static final int LONG_TIMEOUT = 2000;
44     public static final String EDIT_TEXT_CLASS_NAME = "android.widget.EditText";
45     public static final String CAMERA2_PACKAGE = "com.android.camera2";
46     public static final String CAMERA_PACKAGE = "com.google.android.GoogleCamera";
47     public static final String MODE_PIN = "PIN";
48     public static final String MODE_PASSWORD = "Password";
49     public static final String MODE_PATTERN = "Pattern";
50     private static final int SWIPE_MARGIN = 5;
51     private static final int SWIPE_MARGIN_BOTTOM = 100;
52     private static final int DEFAULT_FLING_STEPS = 5;
53     private static final int DEFAULT_SCROLL_STEPS = 15;
54     private static final String PIN_ENTRY = "com.android.systemui:id/pinEntry";
55     private static final String SET_PIN_COMMAND = "locksettings set-pin %s";
56     private static final String SET_PASSWORD_COMMAND = "locksettings set-password %s";
57     private static final String SET_PATTERN_COMMAND = "locksettings set-pattern %s";
58     private static final String CLEAR_COMMAND = "locksettings clear --old %s";
59     private static final String HOTSEAT = "hotseat";
60     private static final BySelector DONE_BUTTON =
61             By.res("com.android.settings", "redaction_done_button");
62 
63     private static LockscreenHelper sInstance = null;
64     private Context mContext = null;
65     private UiDevice mDevice = null;
66     private final ActivityHelper mActivityHelper;
67     private final CommandsHelper mCommandsHelper;
68     private final DeviceHelper mDeviceHelper;
69     private boolean mIsRyuDevice = false;
70 
LockscreenHelper()71     public LockscreenHelper() {
72         mContext = InstrumentationRegistry.getTargetContext();
73         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
74         mActivityHelper = ActivityHelper.getInstance();
75         mCommandsHelper = CommandsHelper.getInstance(InstrumentationRegistry.getInstrumentation());
76         mDeviceHelper = DeviceHelper.getInstance();
77         mIsRyuDevice = mDeviceHelper.isRyuDevice();
78     }
79 
getInstance()80     public static LockscreenHelper getInstance() {
81         if (sInstance == null) {
82             sInstance = new LockscreenHelper();
83         }
84         return sInstance;
85     }
86 
getLauncherPackage()87     public String getLauncherPackage() {
88         return mDevice.getLauncherPackageName();
89     }
90 
91     /**
92      * Launch Camera on LockScreen
93      * @return true/false
94      */
launchCameraOnLockScreen()95     public boolean launchCameraOnLockScreen() {
96         // Hit the back button to dismiss any keyguard
97         mDevice.pressBack();
98         String CameraPackage = mIsRyuDevice ? CAMERA2_PACKAGE : CAMERA_PACKAGE;
99         int w = mDevice.getDisplayWidth();
100         int h = mDevice.getDisplayHeight();
101         // Load camera on LockScreen and take a photo
102         mDevice.drag((w - 25), (h - 25), (int) (w * 0.5), (int) (w * 0.5), 40);
103         mDevice.waitForIdle();
104         return mDevice.wait(Until.hasObject(
105                 By.res(CameraPackage, "activity_root_view")),
106                 LONG_TIMEOUT * 2);
107     }
108 
109      /**
110      * Sets the screen lock pin or password
111      * @param pwd text of Password or Pin for lockscreen
112      * @param mode indicate if its password or PIN
113      * @throws InterruptedException
114      */
setScreenLock(String pwd, String mode, boolean mIsNexusDevice)115     public void setScreenLock(String pwd, String mode, boolean mIsNexusDevice)
116             throws InterruptedException {
117         if (mode.equalsIgnoreCase("None")) {
118             mDevice.wait(Until.findObject(By.text("None")), LONG_TIMEOUT * 2).click();
119             return;
120         }
121         enterScreenLockOnce(pwd, mode, mIsNexusDevice);
122         Thread.sleep(LONG_TIMEOUT);
123         // Re-enter password on confirmation screen
124         UiObject2 pinField = mDevice.wait(Until.findObject(By.clazz(EDIT_TEXT_CLASS_NAME)),
125                 LONG_TIMEOUT);
126         pinField.setText(pwd);
127         Thread.sleep(LONG_TIMEOUT);
128         mDevice.pressEnter();
129         // Click DONE on lock screen notification setting screen
130         mDevice.wait(Until.findObject(DONE_BUTTON), LONG_TIMEOUT).click();
131     }
132 
133     /**
134      * Enters the screen lock once on the setting screen
135      * @param pwd text of Password or Pin for lockscreen
136      * @param mode indicate if its password or PIN
137      * @throws InterruptedException
138      */
enterScreenLockOnce(String pwd, String mode, boolean mIsNexusDevice)139     public void enterScreenLockOnce(String pwd, String mode, boolean mIsNexusDevice) {
140         mDevice.wait(Until.findObject(By.text(mode)), LONG_TIMEOUT * 2).click();
141         // set up Secure start-up page
142         if (!mIsNexusDevice) {
143             mDevice.wait(Until.findObject(By.text("No thanks")), LONG_TIMEOUT).click();
144         }
145         UiObject2 pinField = mDevice.wait(Until.findObject(By.clazz(EDIT_TEXT_CLASS_NAME)),
146                 LONG_TIMEOUT);
147         pinField.setText(pwd);
148         // enter
149         mDevice.pressEnter();
150     }
151 
152     /*
153      * Enters non matching passcodes on both setting screens.
154      * Note: this will fail if you enter matching passcodes.
155      */
enterNonMatchingPasscodes(String firstPasscode, String secondPasscode, String mode, boolean mIsNexusDevice)156     public void enterNonMatchingPasscodes(String firstPasscode, String secondPasscode,
157             String mode, boolean mIsNexusDevice) throws Exception {
158         enterScreenLockOnce(firstPasscode, mode, mIsNexusDevice);
159         Thread.sleep(LONG_TIMEOUT);
160         UiObject2 pinField = mDevice.wait(Until.findObject(By.clazz(EDIT_TEXT_CLASS_NAME)),
161                 LONG_TIMEOUT);
162         pinField.setText(secondPasscode);
163         mDevice.pressEnter();
164         Thread.sleep(LONG_TIMEOUT);
165         // Verify that error is thrown.
166         UiObject2 dontMatchMessage = mDevice.wait(Until.findObject
167                 (By.textContains("don’t match")), LONG_TIMEOUT);
168         Assert.assertNotNull("Error message for passcode confirmation not visible",
169                 dontMatchMessage);
170     }
171 
172     /**
173      * check if Emergency Call page exists
174      * @throws InterruptedException
175      */
checkEmergencyCallOnLockScreen()176     public void checkEmergencyCallOnLockScreen() throws InterruptedException {
177         mDevice.pressMenu();
178         mDevice.wait(Until.findObject(By.text("EMERGENCY")), LONG_TIMEOUT).click();
179         Thread.sleep(LONG_TIMEOUT);
180         UiObject2 dialButton = mDevice.wait(Until.findObject(By.desc("dial")),
181                 LONG_TIMEOUT);
182         Assert.assertNotNull("Can't reach emergency call page", dialButton);
183         mDevice.pressBack();
184         Thread.sleep(LONG_TIMEOUT);
185     }
186 
187     /**
188      * remove Screen Lock, reset to Swipe.
189      * @throws InterruptedException
190      */
removeScreenLock(String pwd)191     public void removeScreenLock(String pwd)
192             throws InterruptedException {
193         navigateToScreenLock();
194         UiObject2 pinField = mDevice.wait(Until.findObject(By.clazz(EDIT_TEXT_CLASS_NAME)),
195                 LONG_TIMEOUT);
196         pinField.setText(pwd);
197         mDevice.pressEnter();
198         mDevice.wait(Until.findObject(By.text("Swipe")), LONG_TIMEOUT).click();
199         mDevice.waitForIdle();
200         mDevice.wait(Until.findObject(By.text(
201                 Pattern.compile("YES, REMOVE", Pattern.CASE_INSENSITIVE))), LONG_TIMEOUT).click();
202     }
203 
204     /**
205      * Enter a screen password or PIN.
206      * Pattern not supported, please use
207      * unlockDeviceWithPattern(String) below.
208      * Method assumes the device is on lockscreen.
209      * with keyguard exposed. It will wake
210      * up the device, swipe up to reveal the keyguard,
211      * and enter the password or pin and hit enter.
212      * @throws InterruptedException, IOException
213      */
unlockScreen(String pwd)214     public void unlockScreen(String pwd)
215             throws InterruptedException, IOException {
216         // Press menu key (82 is the code for the menu key)
217         String command = String.format(" %s %s %s", "input", "keyevent", "82");
218         mDevice.executeShellCommand(command);
219         Thread.sleep(SHORT_TIMEOUT);
220         Thread.sleep(SHORT_TIMEOUT);
221         // enter password to unlock screen
222         command = String.format(" %s %s %s", "input", "text", pwd);
223         mDevice.executeShellCommand(command);
224         mDevice.waitForIdle();
225         Thread.sleep(SHORT_TIMEOUT);
226         mDevice.pressEnter();
227     }
228 
229     /**
230      * navigate to screen lock setting page
231      * @throws InterruptedException
232      */
navigateToScreenLock()233     public void navigateToScreenLock()
234             throws InterruptedException {
235         mActivityHelper.launchIntent(Settings.ACTION_SECURITY_SETTINGS);
236         mDevice.wait(Until.findObject(By.text("Screen lock")), LONG_TIMEOUT).click();
237     }
238 
239     /**
240      * check if Lock Screen is enabled
241      */
isLockScreenEnabled()242     public boolean isLockScreenEnabled() {
243         KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
244         return km.isKeyguardSecure();
245     }
246 
247     /**
248      * Sets a screen lock via shell.
249      */
setScreenLockViaShell(String passcode, String mode)250     public void setScreenLockViaShell(String passcode, String mode) throws Exception {
251         switch (mode) {
252             case MODE_PIN:
253                 mCommandsHelper.executeShellCommand(String.format(SET_PIN_COMMAND, passcode));
254                 break;
255             case MODE_PASSWORD:
256                 mCommandsHelper.executeShellCommand(String.format(SET_PASSWORD_COMMAND, passcode));
257                 break;
258             case MODE_PATTERN:
259                 mCommandsHelper.executeShellCommand(String.format(SET_PATTERN_COMMAND, passcode));
260                 break;
261             default:
262                 throw new IllegalArgumentException("Unsupported mode: " + mode);
263         }
264     }
265 
266     /**
267      * Removes the screen lock via shell.
268      */
removeScreenLockViaShell(String pwd)269     public void removeScreenLockViaShell(String pwd) throws Exception {
270         mCommandsHelper.executeShellCommand(String.format(CLEAR_COMMAND, pwd));
271     }
272 
273     /**
274      * swipe up to unlock the screen
275      */
unlockScreenSwipeUp()276     public void unlockScreenSwipeUp() throws Exception {
277         mDevice.wakeUp();
278         mDevice.waitForIdle();
279         mDevice.swipe(mDevice.getDisplayWidth() / 2,
280                 mDevice.getDisplayHeight() - SWIPE_MARGIN,
281                 mDevice.getDisplayWidth() / 2,
282                 SWIPE_MARGIN,
283                 DEFAULT_SCROLL_STEPS);
284         mDevice.waitForIdle();
285     }
286 
287     /*
288      * Takes in the correct code (pin or password), the attempted
289      * code (pin or password), the mode for the code (whether pin or password)
290      * and whether or not they are expected to match.
291      * Asserts that the device has been successfully unlocked (or not).
292      */
setAndEnterLockscreenCode(String actualCode, String attemptedCode, String mode, boolean shouldMatch)293     public void setAndEnterLockscreenCode(String actualCode, String attemptedCode,
294             String mode, boolean shouldMatch) throws Exception {
295         setScreenLockViaShell(actualCode, mode);
296         Thread.sleep(LONG_TIMEOUT);
297         enterLockscreenCode(actualCode, attemptedCode, mode, shouldMatch);
298     }
299 
enterLockscreenCode(String actualCode, String attemptedCode, String mode, boolean shouldMatch)300     public void enterLockscreenCode(String actualCode, String attemptedCode,
301             String mode, boolean shouldMatch) throws Exception {
302         mDevice.pressHome();
303         mDeviceHelper.sleepAndWakeUpDevice();
304         unlockScreen(attemptedCode);
305         checkForHotseatOnHome(shouldMatch);
306         removeScreenLockViaShell(actualCode);
307         Thread.sleep(LONG_TIMEOUT);
308         mDevice.pressHome();
309     }
310 
311     /*
312      * Takes in the correct pattern, the attempted pattern,
313      * and whether or not they are expected to match.
314      * Asserts that the device has been successfully unlocked (or not).
315      */
setAndEnterLockscreenPattern(String actualPattern, String attemptedPattern, boolean shouldMatch)316     public void setAndEnterLockscreenPattern(String actualPattern,
317         String attemptedPattern, boolean shouldMatch) throws Exception {
318         setScreenLockViaShell
319                 (actualPattern, LockscreenHelper.MODE_PATTERN);
320         unlockDeviceWithPattern(attemptedPattern);
321         checkForHotseatOnHome(shouldMatch);
322         removeScreenLockViaShell(actualPattern);
323         Thread.sleep(LONG_TIMEOUT);
324         mDevice.pressHome();
325     }
326 
checkForHotseatOnHome(boolean deviceUnlocked)327     public void checkForHotseatOnHome(boolean deviceUnlocked)  throws Exception {
328         mDevice.pressHome();
329         Thread.sleep(LONG_TIMEOUT);
330         UiObject2 hotseat = mDevice.findObject(By.res(getLauncherPackage(), HOTSEAT));
331         if (deviceUnlocked) {
332         Assert.assertNotNull("Device not unlocked correctly", hotseat);
333         }
334         else {
335             Assert.assertNull("Device should not be unlocked", hotseat);
336         }
337     }
338 
339     /*
340      * The pattern below is always invalid as you need at least
341      * four dots for a valid lock. That action of changing
342      * directions while dragging is unsupported by
343      * uiautomator.
344      */
enterInvalidPattern()345     public void enterInvalidPattern() throws Exception {
346         // Get coordinates for left top dot
347         UiObject2 lockPattern = mDevice.wait(Until.findObject
348                 (By.res("com.android.systemui:id/lockPatternView")),
349                 LONG_TIMEOUT);
350         // Get coordinates for left side dots
351         int xCoordinate =(int) (lockPattern.getVisibleBounds().left +
352                  lockPattern.getVisibleBounds().left*0.16);
353         int y1Coordinate = (int) (lockPattern.getVisibleBounds().top +
354                 lockPattern.getVisibleBounds().top*0.16);
355         int y2Coordinate = (int) (lockPattern.getVisibleBounds().bottom -
356                 lockPattern.getVisibleBounds().bottom*0.16);
357         // Drag coordinates from one point to another
358         mDevice.swipe(xCoordinate, y1Coordinate, xCoordinate, y2Coordinate, 2);
359     }
360 
361     /* Valid pattern unlock attempt
362      * Takes in a contiguous string as input
363      * 1 2 3
364      * 4 5 6
365      * 7 8 9
366      * with each number representing a dot. Eg: "1236"
367      */
unlockDeviceWithPattern(String unlockPattern)368     public void unlockDeviceWithPattern(String unlockPattern) throws Exception {
369         mDeviceHelper.sleepAndWakeUpDevice();
370         unlockScreenSwipeUp();
371         Point[] coordinateArray = new Point[unlockPattern.length()];
372         for (int i=0; i < unlockPattern.length(); i++) {
373             coordinateArray[i] = calculateCoordinatesForPatternDot(unlockPattern.charAt(i),
374                                  "com.android.systemui:id/lockPatternView");
375         }
376         // Note: 50 controls the speed of the pattern drawing.
377         mDevice.swipe(coordinateArray, 50);
378         Thread.sleep(SHORT_TIMEOUT);
379     }
380 
381     /* Pattern lock setting attempt
382      * Takes in a contiguous string as input
383      * 1 2 3
384      * 4 5 6
385      * 7 8 9
386      * with each number representing a dot. Eg: "1236"
387      */
enterPatternLockOnceForSettingLock(String unlockPattern)388     public void enterPatternLockOnceForSettingLock(String unlockPattern)
389             throws InterruptedException {
390         Point[] coordinateArray = new Point[unlockPattern.length()];
391         for (int i=0; i < unlockPattern.length(); i++) {
392             coordinateArray[i] = calculateCoordinatesForPatternDot(unlockPattern.charAt(i),
393                                  "com.android.settings:id/lockPattern");
394         }
395         // Note: 50 controls the speed of the pattern drawing.
396         mDevice.swipe(coordinateArray, 50);
397         Thread.sleep(SHORT_TIMEOUT);
398     }
399 
400     /* Pattern lock setting - this enters and reconfirms pattern to set
401      * using the UI.
402      * Takes in a contiguous string as input
403      * 1 2 3
404      * 4 5 6
405      * 7 8 9
406      * with each number representing a dot. Eg: "1236"
407      */
setPatternLockSettingLock(String unlockPattern)408     public void setPatternLockSettingLock(String unlockPattern)  throws Exception {
409         // Enter the same pattern twice, once on the initial set
410         // screen and once on the confirmation screen.
411         for (int i=0; i<2; i++) {
412             enterPatternLockOnceForSettingLock(unlockPattern);
413             mDevice.pressEnter();
414         }
415         mDevice.wait(Until.findObject(By.text("DONE")), LONG_TIMEOUT).click();
416     }
417 
418     /* Returns screen coordinates for each pattern dot
419      * for the current device
420      * Represented as follows by chars
421      * 1 2 3
422      * 4 5 6
423      * 7 8 9
424      * this is consistent with the set-pattern command
425      * to avoid confusion.
426      */
calculateCoordinatesForPatternDot(char dotNumber, String lockPatternResId)427     private Point calculateCoordinatesForPatternDot(char dotNumber, String lockPatternResId) {
428         UiObject2 lockPattern = mDevice.wait(Until.findObject
429                 (By.res(lockPatternResId)), LONG_TIMEOUT);
430         // Calculate x coordinate
431         int xCoordinate = 0;
432         int deltaX = (int) ((lockPattern.getVisibleBounds().right -
433                 lockPattern.getVisibleBounds().left)*0.16);
434         if (dotNumber == '1' || dotNumber == '4' || dotNumber == '7') {
435             xCoordinate = lockPattern.getVisibleBounds().left + deltaX;
436         }
437         else if (dotNumber == '2' || dotNumber == '5' || dotNumber == '8') {
438             xCoordinate = lockPattern.getVisibleCenter().x;
439         }
440         else if (dotNumber == '3' || dotNumber == '6' || dotNumber == '9') {
441             xCoordinate = lockPattern.getVisibleBounds().right - deltaX;
442         }
443         // Calculate y coordinate
444         int yCoordinate = 0;
445         int deltaY = (int) ((lockPattern.getVisibleBounds().bottom -
446                 lockPattern.getVisibleBounds().top)*0.16);
447         if (dotNumber == '1' || dotNumber == '2' || dotNumber == '3') {
448             yCoordinate = lockPattern.getVisibleBounds().top + deltaY;
449         }
450         else if (dotNumber == '4' || dotNumber == '5' || dotNumber == '6') {
451             yCoordinate = lockPattern.getVisibleCenter().y;
452         }
453         else if (dotNumber == '7' || dotNumber == '8' || dotNumber == '9') {
454             yCoordinate = lockPattern.getVisibleBounds().bottom - deltaY;
455         }
456         return new Point(xCoordinate, yCoordinate);
457      }
458 }
459