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 17 package com.android.settings.biometrics2.utils; 18 19 20 import static java.lang.String.format; 21 22 import android.app.KeyguardManager; 23 import android.content.Context; 24 import android.os.SystemClock; 25 import android.util.Log; 26 27 import androidx.test.InstrumentationRegistry; 28 import androidx.test.uiautomator.UiDevice; 29 30 import org.junit.Assert; 31 32 import java.io.IOException; 33 import java.util.function.Supplier; 34 35 public class LockScreenUtil { 36 37 private static final String TAG = LockScreenUtil.class.getSimpleName(); 38 39 private static final int SLEEP_MS = 100; 40 private static final int WAIT_TIME_MS = 10000; 41 42 private static final String SET_PATTERN_COMMAND = "locksettings set-pattern"; 43 private static final String SET_PASSWORD_COMMAND = "locksettings set-password"; 44 private static final String SET_PIN_COMMAND = "locksettings set-pin"; 45 46 private static final String RESET_LOCKSCREEN_SHELL_COMMAND = "locksettings clear --old"; 47 48 /** 49 * Different way to set the Lockscreen for Android device. Currently we only support PIN, 50 * PATTERN and PASSWORD 51 * 52 * @param lockscreenType it enum with list of supported lockscreen type 53 * @param lockscreenCode code[PIN or PATTERN or PASSWORD] which needs to be set. 54 * @param expectedResult expected result after setting the lockscreen because for lock type 55 * Swipe and None Keygaurd#isKeyguardSecure remain unlocked i.e. false 56 */ setLockscreen(LockscreenType lockscreenType, String lockscreenCode, boolean expectedResult)57 public static void setLockscreen(LockscreenType lockscreenType, String lockscreenCode, 58 boolean expectedResult) { 59 Log.d(TAG, format("Setting Lockscreen [%s(%s)]", lockscreenType, lockscreenCode)); 60 switch (lockscreenType) { 61 case PIN: 62 executeShellCommand(format("%s %s", SET_PIN_COMMAND, lockscreenCode)); 63 break; 64 case PASSWORD: 65 executeShellCommand(format("%s %s", SET_PASSWORD_COMMAND, lockscreenCode)); 66 break; 67 case PATTERN: 68 executeShellCommand(format("%s %s", SET_PATTERN_COMMAND, lockscreenCode)); 69 break; 70 default: 71 throw new AssertionError("Non-supported Lockscreen Type: " + lockscreenType); 72 } 73 assertKeyguardSecure(expectedResult); 74 } 75 76 /** 77 * Resets the give lockscreen. 78 * 79 * @param lockscreenCode old code which is currently set. 80 */ resetLockscreen(String lockscreenCode)81 public static void resetLockscreen(String lockscreenCode) { 82 Log.d(TAG, String.format("Re-Setting Lockscreen %s", lockscreenCode)); 83 executeShellCommand( 84 format("%s %s", RESET_LOCKSCREEN_SHELL_COMMAND, lockscreenCode)); 85 assertKeyguardSecure(/* expectedSecure= */ false); 86 } 87 88 89 /** 90 * This method help you execute you shell command. 91 * Example: adb shell pm list packages -f 92 * Here you just need to provide executeShellCommand("pm list packages -f") 93 * 94 * @param command command need to executed. 95 */ executeShellCommand(String command)96 private static void executeShellCommand(String command) { 97 Log.d(TAG, format("Executing Shell Command: %s", command)); 98 try { 99 getUiDevice().executeShellCommand(command); 100 } catch (IOException e) { 101 Log.d(TAG, format("IOException Occurred: %s", e)); 102 } 103 } 104 105 /** 106 * Enum for different types of Lockscreen, PIN, PATTERN and PASSWORD. 107 */ 108 public enum LockscreenType { 109 PIN, 110 PASSWORD, 111 PATTERN 112 } 113 getUiDevice()114 private static UiDevice getUiDevice() { 115 return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 116 } 117 assertKeyguardSecure(boolean expectedSecure)118 private static void assertKeyguardSecure(boolean expectedSecure) { 119 waitForCondition( 120 () -> String.format("Assert that keyguard %s secure, but failed.", 121 expectedSecure ? "is" : "isn't"), 122 () -> getKeyguardManager().isKeyguardSecure() == expectedSecure); 123 } 124 125 /** 126 * Waits for a condition and fails if it doesn't become true within 10 sec. 127 * 128 * @param message Supplier of the error message. 129 * @param condition Condition. 130 */ waitForCondition( Supplier<String> message, Condition condition)131 private static void waitForCondition( 132 Supplier<String> message, Condition condition) { 133 waitForCondition(message, condition, WAIT_TIME_MS); 134 } 135 136 /** 137 * Waits for a condition and fails if it doesn't become true within specified time period. 138 * 139 * @param message Supplier of the error message. 140 * @param condition Condition. 141 * @param timeoutMs Timeout. 142 */ waitForCondition( Supplier<String> message, Condition condition, long timeoutMs)143 private static void waitForCondition( 144 Supplier<String> message, Condition condition, long timeoutMs) { 145 final long startTime = SystemClock.uptimeMillis(); 146 while (SystemClock.uptimeMillis() < startTime + timeoutMs) { 147 try { 148 if (condition.isTrue()) { 149 return; 150 } 151 } catch (Throwable t) { 152 throw new RuntimeException(t); 153 } 154 SystemClock.sleep(SLEEP_MS); 155 } 156 157 // Check once more before failing. 158 try { 159 if (condition.isTrue()) { 160 return; 161 } 162 } catch (Throwable t) { 163 throw new RuntimeException(t); 164 } 165 166 Assert.fail(message.get()); 167 } 168 169 /** 170 * To get an instance of class that can be used to lock and unlock the keygaurd. 171 * 172 * @return an instance of class that can be used to lock and unlock the screen. 173 */ getKeyguardManager()174 private static KeyguardManager getKeyguardManager() { 175 return (KeyguardManager) InstrumentationRegistry.getContext().getSystemService( 176 Context.KEYGUARD_SERVICE); 177 } 178 179 /** Supplier of a boolean that can throw an exception. */ 180 private interface Condition { isTrue()181 boolean isTrue() throws Throwable; 182 } 183 } 184