Wednesday, October 21, 2015

Hide Soft Keyboard in Android Emulator/Device

There are multiple strategies for hiding the keyboard:

Method -1
There is a direct method available in AndroidDriver (or if you are using appium for mobile test automation, this method is availale in AppiumDriver too)
For example,
AndroidDriver<WebElement>  driver = new AndroidDriver<WebElement>(
    new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
driver.hideKeyboard();

Method-2
You can hide soft keyboard completely(or only for some test specific) by passing the following property to the desired capabilities as below:
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("unicodeKeyboard", "true");

Method-3
You can hide by clicking different android keys like "Done" or "Back". Here is an example of hiding soft keyboard using BACK key.
driver.pressKeyCode(AndroidKeyCode.BACK);
In some older versions of AndroidDriver you can find below method
((AndroidDriver) driver).sendKeyEvent(AndroidKeyCode.BACK);

Method-4
You can go back by using following code, which will hide your soft keyboard
driver.navigate().back();
This you need to call only after entering text into edit field. For some views or activities, it may go back to the previous activity.

Method-5
You may try the below if it works for you. In some cases this doesn't work well.
HashMap keycode = new HashMap();
keycode.put("keycode", 4);
((JavascriptExecutor)driver).executeScript("mobile: keyevent", keycode);
Method-6
If you have android application code base integrated with your android test base, you can use the below code which will perform based on your current activity.
public void hideSoftKeyboard(Activity activity) {
  InputMethodManager imm = (InputMethodManager)
  activity.getSystemService(Context.INPUT_METHOD_SERVICE);
  imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Monday, October 12, 2015

Start and Stop Appium Server Programmatically

Pre-requisites:
I assume you have installed the followings in your machine already.
Appium is downloaded (latest from here) and setup properly as mentioned here.
Java Development Kit(JDK) is downloaded(refer here) and installed in your machine.

How to Start or Stop appium server programmatically?
Please refer the below class for detailed usage, Hope it is self explanatory.

Method-1:
package appium.base;

import java.io.File;

import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;

/**
 * This page models Appium server
 * 
 * @author A. K. Sahu
 *
 */
public class AppiumServer {

 String appiumInstallationDir = "C:/Program Files (x86)";// e.g. in Windows
 //String appiumInstallationDir = "/Applications";// e.g. for Mac
 AppiumDriverLocalService service = null;

 public AppiumServer() {
  File classPathRoot = new File(System.getProperty("user.dir"));
  String osName = System.getProperty("os.name");

  if (osName.contains("Windows")) {
   service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder()
     .usingDriverExecutable(new File(appiumInstallationDir + File.separator + "Appium" + File.separator + "node.exe"))
     .withAppiumJS(new File(appiumInstallationDir + File.separator + "Appium" + File.separator
       + "node_modules" + File.separator + "appium" + File.separator + "bin" + File.separator + "appium.js"))
     .withLogFile(new File(new File(classPathRoot, File.separator + "log"), "androidLog.txt")));

  } else if (osName.contains("Mac")) {
   service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder()
     .usingDriverExecutable(new File(appiumInstallationDir + "/Appium.app/Contents/Resources/node/bin/node"))
     .withAppiumJS(new File(
       appiumInstallationDir + "/Appium.app/Contents/Resources/node_modules/appium/bin/appium.js"))
     .withLogFile(new File(new File(classPathRoot, File.separator + "log"), "androidLog.txt")));

  } else {
   // you can add for other OS, just to track added a fail message
   Assert.fail("Starting appium is not supporting the current OS.");
  }
 }

 /**
  * Starts appium server
  */
 public void startAppiumServer() {
  service.start();
 }

 /**
  * Stops appium server
  */
 public void stopAppiumServer() {
  service.stop();
 }
}

Usage of this class:
AppiumServer service = new AppiumServer();

// Starts appium server
service.startAppiumServer();

// ... your tests are here. 

// Stops appium server
service.stopAppiumServer();
Note: You can call start appium server in the @BeforeSuite configuration method and stop appium server at @AfterSuite configuration methods.

With the above approach of starting appium server, you can get total android log in the provided log file i.e. "androidlog.txt" file inside "log" directory of your project root directory

Method-2
Here is an another way of starting and killing appium server programmatically using command line executions with java's ProcessBuilder class. Refer below class for more details.
Define the below properties and change as per your appium installation.
 String appiumInstallationDir = "C:/Program Files (x86)";
 String appiumNode = appiumInstallationDir + File.separator + "Appium" + File.separator + "node.exe";
 String appiumNodeModule = appiumInstallationDir + File.separator + "Appium" + File.separator + "node_modules"
   + File.separator + "appium" + File.separator + "bin" + File.separator + "Appium.js";
 String appiumServicePort = "4723";
Execute the start and stop commands like we do from command line but here with using java's ProcessBuilder class.
 /**
  * Starts appium server
  */
 public void startAppiumServer() {
  executeCommand("\"" + appiumNode + "\" \"" + appiumNodeModule 
                      + "\" " + "--no-reset --local-timezone");
 }

 /**
  * Stops appium server
  */
 public void stopAppiumServer() {
 executeCommand("cmd /c echo off & FOR /F \"usebackq tokens=5\" %a in" 
  + " (`netstat -nao ^| findstr /R /C:\""
  + appiumServicePort + "\"`) do (FOR /F \"usebackq\" %b in"
  + " (`TASKLIST /FI \"PID eq %a\" ^| findstr /I node.exe`) do taskkill /F /PID %a)");
}
You may need the below class for executing a command line command. This you can do using Runtime.getRuntime().exec(command) also, but I would suggest to use ProcssBuilder as this is recommended.
 /**
  * Executes any command for Windows using ProcessBuilder of Java You can
  * change the first input parameter of ProcessBuilder constructor if your OS
  * is not windows operating system
  * 
  * @param aCommand
  */
 public void executeCommand(String aCommand) {
  File currDir = new File(System.getProperty("user.dir"));
  String line;
  try {
   ProcessBuilder probuilder = new ProcessBuilder("CMD", "/C", aCommand);
   probuilder.directory(currDir);
   Process process = probuilder.start();

   BufferedReader inputStream 
        = new BufferedReader(new InputStreamReader(process.getInputStream()));
   BufferedReader errorStream 
        = new BufferedReader(new InputStreamReader(process.getErrorStream()));

   // reading output of the command
   int inputLine = 0;
   while ((line = inputStream.readLine()) != null) {
    if (inputLine == 0) {
     System.out.printf("Output of the running command is: \n");
    }
    System.out.println(line);
    inputLine++;
   }

   // reading errors from the command
   int errLine = 0;
   while ((line = errorStream.readLine()) != null) {
    if (errLine == 0) {
     System.out.println("Error of the command is: \n");
    }
    System.out.println(line);
    errLine++;
   }

  } catch (IOException e) {
   System.err.println("Exception occured: \n");
   System.err.println(e.getMessage());
  }
 }

With the above method, the server log will be printed in the console as I kept standard output and error statements. You can change to trace these log in a log file if you need it.

Hope it is useful !!