From c8946c1e95ad8527fe3ad4aff7ed16ba279d399a Mon Sep 17 00:00:00 2001 From: Ali Kia Date: Tue, 21 Nov 2017 13:33:01 +0800 Subject: [PATCH 1/4] add finger print command to android Driver --- .../io/appium/java_client/MobileCommand.java | 3 + .../io/appium/java_client/PressesKeyCode.java | 10 ++ .../android/AndroidMobileCommandHelper.java | 13 ++ .../java_client/android/FingerPrintTest.java | 141 ++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 src/test/java/io/appium/java_client/android/FingerPrintTest.java diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index d4a57044f..bb43506ff 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -68,6 +68,7 @@ public class MobileCommand { protected static final String IS_KEYBOARD_SHOWN; protected static final String IS_LOCKED; protected static final String LONG_PRESS_KEY_CODE; + protected static final String FINGER_PRINT; protected static final String OPEN_NOTIFICATIONS; protected static final String PRESS_KEY_CODE; protected static final String PUSH_FILE; @@ -116,6 +117,7 @@ public class MobileCommand { IS_KEYBOARD_SHOWN = "isKeyboardShown"; IS_LOCKED = "isLocked"; LONG_PRESS_KEY_CODE = "longPressKeyCode"; + FINGER_PRINT = "fingerPrint"; OPEN_NOTIFICATIONS = "openNotifications"; PRESS_KEY_CODE = "pressKeyCode"; PUSH_FILE = "pushFile"; @@ -170,6 +172,7 @@ public class MobileCommand { commandRepository.put(IS_LOCKED, postC("/session/:sessionId/appium/device/is_locked")); commandRepository.put(LONG_PRESS_KEY_CODE, postC("/session/:sessionId/appium/device/long_press_keycode")); + commandRepository.put(FINGER_PRINT, postC("/session/:sessionId/appium/device/finger_print")); commandRepository.put(OPEN_NOTIFICATIONS, postC("/session/:sessionId/appium/device/open_notifications")); commandRepository.put(PRESS_KEY_CODE, diff --git a/src/main/java/io/appium/java_client/PressesKeyCode.java b/src/main/java/io/appium/java_client/PressesKeyCode.java index 4ad06f104..fcd5794f0 100644 --- a/src/main/java/io/appium/java_client/PressesKeyCode.java +++ b/src/main/java/io/appium/java_client/PressesKeyCode.java @@ -18,6 +18,7 @@ import static io.appium.java_client.MobileCommand.longPressKeyCodeCommand; import static io.appium.java_client.MobileCommand.pressKeyCodeCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.fingerPrintCommand; public interface PressesKeyCode extends ExecutesMethod { @@ -41,6 +42,15 @@ default void pressKeyCode(int key, Integer metastate) { CommandExecutionHelper.execute(this, pressKeyCodeCommand(key, metastate)); } + /** + * Authenticate users by using their finger print scans on supported emulators. + * + * @param fingerPrintId finger prints stored in Android Keystore system (from 1 to 10) + */ + default void fingerPrint(int fingerPrintId) { + CommandExecutionHelper.execute(this, fingerPrintCommand(fingerPrintId)); + } + /** * Send a long key event to the device. * diff --git a/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java index 9a13d73ce..375eed815 100644 --- a/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java +++ b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java @@ -184,6 +184,19 @@ public class AndroidMobileCommandHelper extends MobileCommand { IS_LOCKED, ImmutableMap.of()); } + /** + * This method forms a {@link java.util.Map} of parameters for the + * finger print authentication invocation. + * + * @param fingerPrintId finger prints stored in Android Keystore system (from 1 to 10) + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> fingerPrintCommand(int fingerPrintId) { + return new AbstractMap.SimpleEntry<>(FINGER_PRINT, + prepareArguments("fingerprintId", fingerPrintId)); + } + /** * This method forms a {@link java.util.Map} of parameters for the * notification opening. diff --git a/src/test/java/io/appium/java_client/android/FingerPrintTest.java b/src/test/java/io/appium/java_client/android/FingerPrintTest.java new file mode 100644 index 000000000..cc850efc4 --- /dev/null +++ b/src/test/java/io/appium/java_client/android/FingerPrintTest.java @@ -0,0 +1,141 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client.android; + +import io.appium.java_client.remote.MobileCapabilityType; +import io.appium.java_client.service.local.AppiumDriverLocalService; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.util.concurrent.TimeUnit; + +public class FingerPrintTest { + + private static final String PASSWORD_INPUT_ID = "com.android.settings:id/password_entry"; + private static final String FIRST_IN_LIST_XPATH = "//android.widget.ListView[1]/android.widget.LinearLayout[1]"; + private static AppiumDriverLocalService service; + + /** + * initialization. + */ + @BeforeClass public static void beforeClass() { + service = AppiumDriverLocalService.buildDefaultService(); + service.start(); + + if (service == null || !service.isRunning()) { + throw new ExceptionInInitializerError("An appium server node is not started!"); + } + } + + /** + * finishing. + */ + @AfterClass public static void afterClass() { + if (service != null) { + service.stop(); + } + } + + /** + * enable system security which is required for finger print activation. + */ + @Before public void before() throws Exception { + final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); + TimeUnit.SECONDS.sleep(2); + // clicking the pin lock mode + driver.findElement(By.xpath("//android.widget.LinearLayout[4]")).click(); + TimeUnit.SECONDS.sleep(2); + try { + // line below will throw exception if secure startup window is popped up + driver.findElementById(PASSWORD_INPUT_ID); + } catch (NoSuchElementException e) { + // in secure startup window + driver.findElementById("com.android.settings:id/encrypt_require_password").click(); + TimeUnit.SECONDS.sleep(2); + clickOKInPopup(driver); + clickNext(driver); + } + enterPasswordAndContinue(driver); + enterPasswordAndContinue(driver); + clickNext(driver); + driver.quit(); + } + + /** + * add a new finger print to security. + */ + @Test public void pressKeyCodeTest() throws InterruptedException { + final AndroidDriver driver = getAndroidDriver(".fingerprint.FingerprintSettings"); + TimeUnit.SECONDS.sleep(2); + enterPasswordAndContinue(driver); + // click add fingerprint + driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); + TimeUnit.SECONDS.sleep(2); + driver.fingerPrint(2); + TimeUnit.SECONDS.sleep(2); + try { + clickNext(driver); + } catch (Exception e) { + Assert.fail("fingerprint command fail to execute"); + } finally { + driver.quit(); + } + } + + /** + * disabling pin lock mode. + */ + @After public void after() throws InterruptedException { + final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); + TimeUnit.SECONDS.sleep(2); + enterPasswordAndContinue(driver); + driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); + TimeUnit.SECONDS.sleep(2); + clickOKInPopup(driver); + driver.quit(); + } + + private AndroidDriver getAndroidDriver(String activity) { + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator"); + capabilities.setCapability("appPackage", "com.android.settings"); + capabilities.setCapability("appActivity", activity); + return new AndroidDriver(service.getUrl(), capabilities); + } + + private void enterPasswordAndContinue(AndroidDriver driver) throws InterruptedException { + driver.findElementById(PASSWORD_INPUT_ID).sendKeys("1234\n"); + TimeUnit.SECONDS.sleep(2); + } + + private void clickNext(AndroidDriver driver) throws InterruptedException { + driver.findElementById("com.android.settings:id/next_button").click(); + TimeUnit.SECONDS.sleep(2); + } + + private void clickOKInPopup(AndroidDriver driver) throws InterruptedException { + driver.findElementById("android:id/button1").click(); + TimeUnit.SECONDS.sleep(2); + } +} From 0a3f46330c2bf36e9824fa09356f7cfc8d81d649 Mon Sep 17 00:00:00 2001 From: Sergey Tikhomirov Date: Mon, 11 Dec 2017 22:52:42 +0300 Subject: [PATCH 2/4] Additional changes of the #473: - AuthenticatesByFinger was added to `io.appium.java_client.android` - Some improvements of the FingerPrintTest --- .../io/appium/java_client/PressesKeyCode.java | 10 ------- .../java_client/android/AndroidDriver.java | 2 +- .../android/AuthenticatesByFinger.java | 18 +++++++++++++ .../java_client/android/FingerPrintTest.java | 27 +++++++++---------- 4 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 src/main/java/io/appium/java_client/android/AuthenticatesByFinger.java diff --git a/src/main/java/io/appium/java_client/PressesKeyCode.java b/src/main/java/io/appium/java_client/PressesKeyCode.java index fcd5794f0..4ad06f104 100644 --- a/src/main/java/io/appium/java_client/PressesKeyCode.java +++ b/src/main/java/io/appium/java_client/PressesKeyCode.java @@ -18,7 +18,6 @@ import static io.appium.java_client.MobileCommand.longPressKeyCodeCommand; import static io.appium.java_client.MobileCommand.pressKeyCodeCommand; -import static io.appium.java_client.android.AndroidMobileCommandHelper.fingerPrintCommand; public interface PressesKeyCode extends ExecutesMethod { @@ -42,15 +41,6 @@ default void pressKeyCode(int key, Integer metastate) { CommandExecutionHelper.execute(this, pressKeyCodeCommand(key, metastate)); } - /** - * Authenticate users by using their finger print scans on supported emulators. - * - * @param fingerPrintId finger prints stored in Android Keystore system (from 1 to 10) - */ - default void fingerPrint(int fingerPrintId) { - CommandExecutionHelper.execute(this, fingerPrintCommand(fingerPrintId)); - } - /** * Send a long key event to the device. * diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java index fc29f9ecb..129ae01ea 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -47,7 +47,7 @@ public class AndroidDriver extends AppiumDriver implements PressesKeyCode, HasNetworkConnection, PushesFiles, StartsActivity, FindsByAndroidUIAutomator, LocksAndroidDevice, HasAndroidSettings, HasDeviceDetails, - HasSupportedPerformanceDataType { + HasSupportedPerformanceDataType, AuthenticatesByFinger { private static final String ANDROID_PLATFORM = MobilePlatform.ANDROID; diff --git a/src/main/java/io/appium/java_client/android/AuthenticatesByFinger.java b/src/main/java/io/appium/java_client/android/AuthenticatesByFinger.java new file mode 100644 index 000000000..717d5150d --- /dev/null +++ b/src/main/java/io/appium/java_client/android/AuthenticatesByFinger.java @@ -0,0 +1,18 @@ +package io.appium.java_client.android; + +import static io.appium.java_client.android.AndroidMobileCommandHelper.fingerPrintCommand; + +import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.ExecutesMethod; + +public interface AuthenticatesByFinger extends ExecutesMethod { + + /** + * Authenticate users by using their finger print scans on supported emulators. + * + * @param fingerPrintId finger prints stored in Android Keystore system (from 1 to 10) + */ + default void fingerPrint(int fingerPrintId) { + CommandExecutionHelper.execute(this, fingerPrintCommand(fingerPrintId)); + } +} diff --git a/src/test/java/io/appium/java_client/android/FingerPrintTest.java b/src/test/java/io/appium/java_client/android/FingerPrintTest.java index cc850efc4..3c46181c1 100644 --- a/src/test/java/io/appium/java_client/android/FingerPrintTest.java +++ b/src/test/java/io/appium/java_client/android/FingerPrintTest.java @@ -16,6 +16,8 @@ package io.appium.java_client.android; +import static java.util.concurrent.TimeUnit.SECONDS; + import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.service.local.AppiumDriverLocalService; import org.junit.After; @@ -28,8 +30,11 @@ import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.remote.DesiredCapabilities; -import java.util.concurrent.TimeUnit; - +/** + * It is necessary to make this test passing + * - emulator API Level 23 Nexus device + * - perform 'adb emu finger touch' 1 on Windows + */ public class FingerPrintTest { private static final String PASSWORD_INPUT_ID = "com.android.settings:id/password_entry"; @@ -62,17 +67,15 @@ public class FingerPrintTest { */ @Before public void before() throws Exception { final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); - TimeUnit.SECONDS.sleep(2); // clicking the pin lock mode driver.findElement(By.xpath("//android.widget.LinearLayout[4]")).click(); - TimeUnit.SECONDS.sleep(2); try { // line below will throw exception if secure startup window is popped up driver.findElementById(PASSWORD_INPUT_ID); } catch (NoSuchElementException e) { // in secure startup window driver.findElementById("com.android.settings:id/encrypt_require_password").click(); - TimeUnit.SECONDS.sleep(2); + SECONDS.sleep(2); clickOKInPopup(driver); clickNext(driver); } @@ -87,13 +90,10 @@ public class FingerPrintTest { */ @Test public void pressKeyCodeTest() throws InterruptedException { final AndroidDriver driver = getAndroidDriver(".fingerprint.FingerprintSettings"); - TimeUnit.SECONDS.sleep(2); enterPasswordAndContinue(driver); // click add fingerprint driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); - TimeUnit.SECONDS.sleep(2); driver.fingerPrint(2); - TimeUnit.SECONDS.sleep(2); try { clickNext(driver); } catch (Exception e) { @@ -108,34 +108,31 @@ public class FingerPrintTest { */ @After public void after() throws InterruptedException { final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); - TimeUnit.SECONDS.sleep(2); enterPasswordAndContinue(driver); driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); - TimeUnit.SECONDS.sleep(2); clickOKInPopup(driver); driver.quit(); } - private AndroidDriver getAndroidDriver(String activity) { + private static AndroidDriver getAndroidDriver(String activity) { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator"); capabilities.setCapability("appPackage", "com.android.settings"); capabilities.setCapability("appActivity", activity); - return new AndroidDriver(service.getUrl(), capabilities); + AndroidDriver driver = new AndroidDriver(service.getUrl(), capabilities); + driver.manage().timeouts().implicitlyWait(15, SECONDS); + return driver; } private void enterPasswordAndContinue(AndroidDriver driver) throws InterruptedException { driver.findElementById(PASSWORD_INPUT_ID).sendKeys("1234\n"); - TimeUnit.SECONDS.sleep(2); } private void clickNext(AndroidDriver driver) throws InterruptedException { driver.findElementById("com.android.settings:id/next_button").click(); - TimeUnit.SECONDS.sleep(2); } private void clickOKInPopup(AndroidDriver driver) throws InterruptedException { driver.findElementById("android:id/button1").click(); - TimeUnit.SECONDS.sleep(2); } } From 2585bba4816a031caebbe01606f3bda168763a2f Mon Sep 17 00:00:00 2001 From: Sergey Tikhomirov Date: Sun, 17 Dec 2017 02:36:27 +0300 Subject: [PATCH 3/4] Additional changes of the #473: improvements of FingerPrintTest --- .../java_client/android/FingerPrintTest.java | 118 +++++++++--------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/src/test/java/io/appium/java_client/android/FingerPrintTest.java b/src/test/java/io/appium/java_client/android/FingerPrintTest.java index 3c46181c1..f7e180910 100644 --- a/src/test/java/io/appium/java_client/android/FingerPrintTest.java +++ b/src/test/java/io/appium/java_client/android/FingerPrintTest.java @@ -16,7 +16,9 @@ package io.appium.java_client.android; +import static io.appium.java_client.MobileBy.AndroidUIAutomator; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.openqa.selenium.By.id; import io.appium.java_client.remote.MobileCapabilityType; import io.appium.java_client.service.local.AppiumDriverLocalService; @@ -26,20 +28,21 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.remote.DesiredCapabilities; -/** - * It is necessary to make this test passing - * - emulator API Level 23 Nexus device - * - perform 'adb emu finger touch' 1 on Windows - */ public class FingerPrintTest { - - private static final String PASSWORD_INPUT_ID = "com.android.settings:id/password_entry"; - private static final String FIRST_IN_LIST_XPATH = "//android.widget.ListView[1]/android.widget.LinearLayout[1]"; private static AppiumDriverLocalService service; + private static AndroidDriver driver; + + private static void initDriver() { + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator"); + capabilities.setCapability("appPackage", "com.android.settings"); + capabilities.setCapability("appActivity", "Settings"); + driver = new AndroidDriver<>(service.getUrl(), capabilities); + driver.manage().timeouts().implicitlyWait(15, SECONDS); + } /** * initialization. @@ -62,44 +65,59 @@ public class FingerPrintTest { } } + private AndroidElement findElementByText(String text) { + return driver.findElements(id("android:id/title")).stream().filter(androidElement -> + text.equals(androidElement.getText())).findFirst() + .orElseThrow(() -> + new NoSuchElementException(String.format("There is no element with the text '%s'", text))); + } + + private void clickNext() { + driver.findElementById("com.android.settings:id/next_button").click(); + } + + private void clickOKInPopup() { + driver.findElementById("android:id/button1").click(); + } + + private void enterPasswordAndContinue() { + driver.findElementById("com.android.settings:id/password_entry") + .sendKeys("1234\n"); + } + + private void clickOnSecurity() { + driver.findElement(AndroidUIAutomator("new UiScrollable(new UiSelector()" + + ".scrollable(true)).scrollIntoView(" + + "new UiSelector().text(\"Security\"));")).click(); + } + /** * enable system security which is required for finger print activation. */ @Before public void before() throws Exception { - final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); - // clicking the pin lock mode - driver.findElement(By.xpath("//android.widget.LinearLayout[4]")).click(); - try { - // line below will throw exception if secure startup window is popped up - driver.findElementById(PASSWORD_INPUT_ID); - } catch (NoSuchElementException e) { - // in secure startup window - driver.findElementById("com.android.settings:id/encrypt_require_password").click(); - SECONDS.sleep(2); - clickOKInPopup(driver); - clickNext(driver); - } - enterPasswordAndContinue(driver); - enterPasswordAndContinue(driver); - clickNext(driver); - driver.quit(); + initDriver(); + clickOnSecurity(); + findElementByText("Screen lock").click(); + findElementByText("PIN").click(); + enterPasswordAndContinue(); + enterPasswordAndContinue(); + clickNext(); } /** * add a new finger print to security. */ - @Test public void pressKeyCodeTest() throws InterruptedException { - final AndroidDriver driver = getAndroidDriver(".fingerprint.FingerprintSettings"); - enterPasswordAndContinue(driver); - // click add fingerprint - driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); + @Test public void fingerPrintTest() { + findElementByText("Fingerprint").click(); + clickNext(); + enterPasswordAndContinue(); + clickNext(); + driver.fingerPrint(2); try { - clickNext(driver); + driver.findElementById("com.android.settings:id/next_button").click(); } catch (Exception e) { Assert.fail("fingerprint command fail to execute"); - } finally { - driver.quit(); } } @@ -107,32 +125,16 @@ public class FingerPrintTest { * disabling pin lock mode. */ @After public void after() throws InterruptedException { - final AndroidDriver driver = getAndroidDriver("ChooseLockGeneric"); - enterPasswordAndContinue(driver); - driver.findElementByXPath(FIRST_IN_LIST_XPATH).click(); - clickOKInPopup(driver); driver.quit(); - } - - private static AndroidDriver getAndroidDriver(String activity) { - DesiredCapabilities capabilities = new DesiredCapabilities(); - capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator"); - capabilities.setCapability("appPackage", "com.android.settings"); - capabilities.setCapability("appActivity", activity); - AndroidDriver driver = new AndroidDriver(service.getUrl(), capabilities); - driver.manage().timeouts().implicitlyWait(15, SECONDS); - return driver; - } - private void enterPasswordAndContinue(AndroidDriver driver) throws InterruptedException { - driver.findElementById(PASSWORD_INPUT_ID).sendKeys("1234\n"); - } + initDriver(); + clickOnSecurity(); - private void clickNext(AndroidDriver driver) throws InterruptedException { - driver.findElementById("com.android.settings:id/next_button").click(); - } + findElementByText("Screen lock").click(); - private void clickOKInPopup(AndroidDriver driver) throws InterruptedException { - driver.findElementById("android:id/button1").click(); + enterPasswordAndContinue(); + findElementByText("None").click(); + clickOKInPopup(); + driver.quit(); } -} +} \ No newline at end of file From eb4116f2409325408f3f90bec9920d3159f93bdb Mon Sep 17 00:00:00 2001 From: Sergey Tikhomirov Date: Sun, 17 Dec 2017 20:24:22 +0300 Subject: [PATCH 4/4] Additional changes of the #473: improvements of FingerPrintTest --- .../java/io/appium/java_client/android/FingerPrintTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/appium/java_client/android/FingerPrintTest.java b/src/test/java/io/appium/java_client/android/FingerPrintTest.java index f7e180910..3c201b78d 100644 --- a/src/test/java/io/appium/java_client/android/FingerPrintTest.java +++ b/src/test/java/io/appium/java_client/android/FingerPrintTest.java @@ -115,7 +115,7 @@ private void clickOnSecurity() { driver.fingerPrint(2); try { - driver.findElementById("com.android.settings:id/next_button").click(); + clickNext(); } catch (Exception e) { Assert.fail("fingerprint command fail to execute"); }