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/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/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/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 new file mode 100644 index 000000000..3c201b78d --- /dev/null +++ b/src/test/java/io/appium/java_client/android/FingerPrintTest.java @@ -0,0 +1,140 @@ +/* + * 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 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; +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.NoSuchElementException; +import org.openqa.selenium.remote.DesiredCapabilities; + +public class FingerPrintTest { + 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. + */ + @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(); + } + } + + 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 { + initDriver(); + clickOnSecurity(); + findElementByText("Screen lock").click(); + findElementByText("PIN").click(); + enterPasswordAndContinue(); + enterPasswordAndContinue(); + clickNext(); + } + + /** + * add a new finger print to security. + */ + @Test public void fingerPrintTest() { + findElementByText("Fingerprint").click(); + clickNext(); + enterPasswordAndContinue(); + clickNext(); + + driver.fingerPrint(2); + try { + clickNext(); + } catch (Exception e) { + Assert.fail("fingerprint command fail to execute"); + } + } + + /** + * disabling pin lock mode. + */ + @After public void after() throws InterruptedException { + driver.quit(); + + initDriver(); + clickOnSecurity(); + + findElementByText("Screen lock").click(); + + enterPasswordAndContinue(); + findElementByText("None").click(); + clickOKInPopup(); + driver.quit(); + } +} \ No newline at end of file