/**
** Copyright (C) SAS Institute, All rights reserved.
** General Public License: http://www.opensource.org/licenses/gpl-license.php
**/
package com.jayway.android.robotium.remotecontrol.solo;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeoutException;
import org.safs.android.auto.lib.DUtilities;
import org.safs.sockets.RemoteException;
import org.safs.sockets.ShutdownInvocationException;
/**
* This is used to test Remote Solo Implementation.<br>
* The tested Activity is "com.android.example.spinner.SpinnerActivity"<br>
* If testing with another Activity, we suggest to subclass this program.<br>
* <p>
*
* <b>Prerequisite:</b>
* <pre>
* 1. Set the android sdk dir (use one of 2 ways):
*
* 1.1 set environment ANDROID_HOME
* 1.2 launch application with JVM property as: -Dandroid-home="D:\\your\\android-sdk-dir"
*
* 2. (Optional)Set the ant sdk dir if you need rebuild the test-runner-apk (use one of 2 ways):
*
* 2.1 set environment ANT_HOME
* 2.2 launch application with JVM property as: -Dant-home="D:\\your\\ant-sdk-dir"
*
* 3. Command-line args to set the APK of AUT, SAFSMessenger and TestRunner to be installed:
*
* aut=D:\\Eclipse\\workspace\\ApiDemos\\bin\\ApiDemos.apk (sets installAUT=true)
* messenger=d:\\buildFilePath\\SAFSTCPMessenger-debug.apk (sets installMessenger=true)
* runner=d:\\buildFilePath\\RobotiumTestRunner-debug.apk (sets installRunner=true)
* (or runnersource=d:\\testRunnerSourcePath like below:)
* runnersource=d:\\Eclipse\\workspace\\android\\SAFSEngine (sets rebuildRunner=true)
*
* OR, to bypass individual installs and use what is already installed:
*
* -noaut
* -nomessenger
* -norunner
*
*
* 4. Command-line arg to set the instrument:
*
* instrument=com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner
*
* 5. Command-line arg to set the avd name to launch, or the device/emulator serial number to look for:
*
* avd="avdName" or avd="devOrEmuSerial"
*
* 6. Command-line arg to set the persistence of launched emulator:
*
* persistavd="True" or persistavd="False" (default=false)
*
* 7. Command-line arg to set to resign AUT automatically:
*
* resignjar=C:\\safs\\lib\\re-sign.jar
*
* </pre>
*
* <p><pre>
* Run as:
*
* java com.jayway.android.robotium.remotecontrol.solo.SoloTest aut=d:\\buildFilePath\\ApiDemos.apk messenger=d:\\buildFilePath\\SAFSTCPMessenger-debug.apk runner=d:\\buildFilePath\\RobotiumTestRunner-debug.apk instrument=com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner
*
* or, rebuild testrunner and use it
* java -Dant-home="C:\\pathTo\\ant-sdk" com.jayway.android.robotium.remotecontrol.solo.SoloTest aut=d:\\buildFilePath\\ApiDemos.apk messenger=d:\\buildFilePath\\SAFSTCPMessenger-debug.apk runnersource=d:\\testRunnerSourcePath\\ instrument=com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner
*
* or, assuming everything is already installed:
*
* java -Dandroid-home="C:\\pathTo\\android-sdk" com.jayway.android.robotium.remotecontrol.solo.SoloTest -noaut -nomessenger -norunner instrument=com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner
*
*
* </pre>
* @author Lei Wang, SAS Institute, Inc.
* @since
* <br>(LeiWang) Mar 09, 2012 Add a field robotiumUtils.
* <br>(LeiWang) Jun 21, 2012 Add a field robotiumTimeout.
*/
public class SoloTest{
public Solo solo = null;
public RobotiumUtils robotiumUtils = null;
public Timeout robotiumTimeout = null;
private boolean enableProtocolDebug = true;
private boolean enableRunnerDebug = true;
private boolean installAUT = true;
private boolean installMessenger = true;
private boolean installRunner = true;
/**
* Rebuilding testrunner will depend on {@link #autApk} and {@link #testRunnerSourceDir}
*
*/
private boolean rebuildRunner = false;
/**
* resignJar is the path to JAR file used to resign<br>
* it will be modified by the value pass in as 'resignjar=' argument<br>
*/
private String resignJar = null;
/**
* autApk is the path to AUT's apk<br>
* it is set to {@link #DEFAULT_AUT_APK} by default<br>
* it will be modified by the value pass in as 'aut=' argument<br>
*/
private String autApk = DEFAULT_AUT_APK;
/**
* messengerApk is the path to messenger's apk<br>
* it is set to {@link #DEFAULT_MESSENGER_APK} by default<br>
* it will be modified by the value pass in as 'messenger=' argument<br>
*/
private String messengerApk = DEFAULT_MESSENGER_APK;
/**
* messengerApk is the path to testrunner's apk<br>
* it is set to {@link #DEFAULT_TESTRUNNER_APK} by default<br>
* it will be modified by the value pass in as 'runner=' argument<br>
*/
private String testRunnerApk = DEFAULT_TESTRUNNER_APK;
/**
* testRunnerSourceDir is the path where the testrunner's source locates<br>
* it is set to {@link #DEFAULT_TESTRUNNER_SOURCE_DIR} by default<br>
* it will be modified by the value pass in as 'runnersource=' argument<br>
*/
private String testRunnerSourceDir = DEFAULT_TESTRUNNER_SOURCE_DIR;
/**
* messengerApk is the path to messenger's apk<br>
* it is set to {@link #DEFAULT_INSTRUMENT_ARG} by default<br>
* it will be modified by the value pass in as 'instrument=' argument<br>
*/
private String instrumentArg = DEFAULT_INSTRUMENT_ARG;
/**
* avdSerialNo is device or emulator's serial number, it is "" by default<br>
* it will be modified by the value pass in as 'avd=' argument<br>
*
* If there is no device/emulator is attached/launched, we will try to<br>
* launch the emulator with this serial number.<br>
* If there is one device/emulator is attached/launched, we will ignore<br>
* this serial number.<br>
* If there are multiple devices/emulators are attached/launched, we<br>
* use this serial number to locate the device/emulator.<br>
*
*/
protected String avdSerialNo = "";
/**
* If this is true, we will keep the launched emulator running even after the<br>
* test has finished.<br>
* The default value is false.<br>
* it will be modified by the value pass in as 'persistavd=' argument<br>
*
*/
protected boolean persistEmulators = false;
protected boolean weLaunchedEmulator = false;
/** flag defaults to true to unlock the screen of any emulator we wish to connect to. */
protected boolean unlockEmulatorScreen = true;
/**
* This field will store the activity UID of you launch AUT.<br>
* It will be set in method {@link #initialize()}<br>
*
* It will be used in method {@link #goBackToViewUID(String)} to prevent infinite loop.<br>
*/
protected String mainActivityUID = null;
/** true if we received the 'aut' command-line argument, or setAUTApk() was called. */
public boolean argAUTpassed = false;
/** true if we received the 'messenger' command-line argument, or setMessengerApk() was called. */
public boolean argMESSENGERpassed = false;
/** true if we received the 'runner' command-line argument, or setTestRunnerApk() was called. */
public boolean argRUNNERpassed = false;
/** true if we received the 'instrument' command-line argument, or setInstrumentArg() was called. */
public boolean argINSTRUMENTpassed = false;
/** true if we received the 'resignjar' command-line argument, or setResignJar() was called. */
public boolean argRESIGNJARpassed = false;
/** true if we received the 'runnersource' command-line argument, or setTestRunnerSourceDir() was called. */
public boolean argRUNNERSOURCEpassed = false;
/**
* Modify {@link #DEFAULT_AUT_APK} according to your system.<br>
* Modify {@link #DEFAULT_MESSENGER_APK} according to your system.<br>
* Modify {@link #DEFAULT_TESTRUNNER_APK} according to your system.<br>
* Modify {@link #DEFAULT_TESTRUNNER_SOURCE_DIR} according to your system.<br>
* Modify {@link #DEFAULT_INSTRUMENT_ARG} according to your system.<br>
*/
public static final String DEFAULT_AUT_APK = "D:\\Eclipse\\workspace\\ApiDemos\\bin\\ApiDemos.apk";
public static final String DEFAULT_MESSENGER_APK = "D:\\Eclipse\\workspace\\android\\SAFSMessenger\\bin\\SAFSTCPMessenger-debug.apk";
public static final String DEFAULT_TESTRUNNER_APK = "D:\\Eclipse\\workspace\\android\\SAFSEngine\\bin\\RobotiumTestRunner-debug.apk";
public static final String DEFAULT_TESTRUNNER_SOURCE_DIR = "D:\\Eclipse\\workspace\\android\\SAFSEngine";
public static final String DEFAULT_INSTRUMENT_ARG = "com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner";
public static final String ARG_KEY_RESIGN_JAR = "resignjar";
public static final String ARG_KEY_AUT_APK = "aut";
public static final String ARG_KEY_MESSENGER_APK = "messenger";
public static final String ARG_KEY_TESTRUNNER_APK = "runner";
public static final String ARG_KEY_TESTRUNNER_SOURCE = "runnersource";
public static final String ARG_KEY_INSTRUMENT_ARG = "instrument";
public static final String ARG_KEY_AVD = "avd";
public static final String ARG_KEY_PERSIST_AVD = "persistavd";
public static final String ARG_KEY_NO_MESSENGER = "-nomessenger";
public static final String ARG_KEY_NO_RUNNER = "-norunner";
public static final String ARG_KEY_NO_AUT = "-noaut";
public SoloTest(){
solo = new Solo();
//By default, we disable the debug message of Protocol/Runner so that the console
//show only the test log message.
setProtocolDebug(false);
setRunnerDebug(false);
}
public SoloTest(String messengerApk, String testRunnerApk, String instrumentArg){
this();
this.messengerApk = messengerApk;
this.testRunnerApk = testRunnerApk;
this.instrumentArg = instrumentArg;
}
/**
* @param args Array of Strings: "aut=xxx", "messenger=xxx", "runner=xxx", "runnersource=xxx", "instrument=xxx", "resignjar=xxx"
*/
public SoloTest(String[] args){
this();
//Get 'apk path' and 'instrument' from program's parameters
//and set them to soloTest object.
String temp = "";
String[] tempArray = null;
for(int i=0;i<args.length;i++){
temp=args[i];
tempArray = temp.split("=");
if(tempArray!=null && tempArray.length==2){
//use temp to contain the parameter key
temp = tempArray[0].trim();
if(ARG_KEY_AUT_APK.equalsIgnoreCase(temp)){
setAUTApk(tempArray[1]);
}else if(ARG_KEY_RESIGN_JAR.equalsIgnoreCase(temp)){
setResignJar(tempArray[1]);
}else if(ARG_KEY_MESSENGER_APK.equalsIgnoreCase(temp)){
setMessengerApk(tempArray[1]);
}else if(ARG_KEY_TESTRUNNER_APK.equalsIgnoreCase(temp)){
setTestRunnerApk(tempArray[1]);
}else if(ARG_KEY_INSTRUMENT_ARG.equalsIgnoreCase(temp)){
setInstrumentArg(tempArray[1]);
}else if(ARG_KEY_TESTRUNNER_SOURCE.equalsIgnoreCase(temp)){
setTestRunnerSourceDir(tempArray[1]);
}else if(ARG_KEY_AVD.equalsIgnoreCase(temp)){
avdSerialNo = tempArray[1];
}else if(ARG_KEY_PERSIST_AVD.equalsIgnoreCase(temp)){
try{ persistEmulators = Boolean.parseBoolean(tempArray[1]);} catch(Exception e){}
}
}else{
if(tempArray.length == 1){
if(ARG_KEY_NO_AUT.equalsIgnoreCase(temp)){
installAUT = false;
}else if(ARG_KEY_NO_MESSENGER.equalsIgnoreCase(temp)){
installMessenger = false;
}else if(ARG_KEY_NO_RUNNER.equalsIgnoreCase(temp)){
installRunner = false;
}
}
}
}
}
public String getTestRunnerSourceDir() {
return testRunnerSourceDir;
}
public void setTestRunnerSourceDir(String testRunnerSourceDir) {
this.testRunnerSourceDir = testRunnerSourceDir;
if(testRunnerSourceDir!=null) {
this.argRUNNERSOURCEpassed = true;
this.setRebuildRunner(true);
}
}
public String getResignJar() {
return resignJar;
}
public void setResignJar(String resignJar) {
this.resignJar = resignJar;
if(resignJar!=null) this.argRESIGNJARpassed = true;
}
public String getAUTApk() {
return autApk;
}
public void setAUTApk(String autApk) {
this.autApk = autApk;
if(autApk!=null) this.argAUTpassed = true;
}
public String getMessengerApk() {
return messengerApk;
}
public void setMessengerApk(String messengerApk) {
this.messengerApk = messengerApk;
if(messengerApk!=null) this.argMESSENGERpassed = true;
}
public String getTestRunnerApk() {
return testRunnerApk;
}
public void setTestRunnerApk(String testRunnerApk) {
this.testRunnerApk = testRunnerApk;
if(testRunnerApk!=null) this.argRUNNERpassed = true;
}
public String getInstrumentArg() {
return instrumentArg;
}
public void setInstrumentArg(String instrumentArg) {
this.instrumentArg = instrumentArg;
if(instrumentArg!=null) this.argINSTRUMENTpassed = true;
}
/**
* Turn on or off the protocol's debug message
* @param enable
*/
public void setProtocolDebug(boolean enableProtocolDebug){
this.enableProtocolDebug = enableProtocolDebug;
}
/**
* Turn on or off the runner's debug message
* @param enable
*/
public void setRunnerDebug(boolean enableRunnerDebug){
this.enableRunnerDebug = enableRunnerDebug;
}
public void setInstallAUT(boolean installAUT) {
this.installAUT = installAUT;
}
public void setInstallMessenger(boolean installMessenger) {
this.installMessenger = installMessenger;
}
public void setInstallRunner(boolean installRunner) {
this.installRunner = installRunner;
}
/**
* Rebuilding testrunner will depend on {@link #autApk} and {@link #testRunnerSourceDir}
*
* @param rebuildRunner
*/
public void setRebuildRunner(boolean rebuildRunner) {
this.rebuildRunner = rebuildRunner;
}
/**
* A template method.<br>
*
* @see #preparation()
* @see #initialize()
* @see #test()
* @see #terminate()
*/
final public void process(){
if(!preparation()){
error("Preparation error");
//stop the emulator if we have launched it.
if(!stopEmulator()){
warn("We fail to stop the emulator launched by us.");
}
return;
}
try{
if(initialize()){
debug("Begin Test.");
test();
debug("End Test.");
}
}catch(Exception e){
error("Met Exception "+e.getClass().getSimpleName()+":"+e.getMessage());
}finally{
//Whether the 'remote engine' has been started or not
//we will call the method terminate() to stop the local controller runner.
if(!terminate()){
warn("Termination of Solo fail!");
}
}
}
/**
* Install the apk of SAFSTCPMessenger and RobotiumTestRunner<br>
* Forward the tcp port from on-computer-2411 to on-device-2410<br>
*
* @return True if the preparation is finished successfully.
*/
final protected boolean preparation(){
String debugPrefix = ".preparation() ";
try{
if(!prepareDevice()){
throw new RuntimeException("Can't detect connected device/emulator!");
}
// 1. Install apks
if (installAUT) {
if(getResignJar()!=null){
debug("RESIGNING " + autApk);
DUtilities.resignAUTApk(resignJar, autApk);
}
debug("INSTALLING " + autApk);
DUtilities.installReplaceAPK(autApk);
} else {
debug("BYPASSING INSTALLATION of target AUT...");
}
if (installMessenger) {
debug("INSTALLING " + messengerApk);
DUtilities.installReplaceAPK(messengerApk);
} else {
debug("BYPASSING INSTALLATION of SAFS Messenger...");
}
// Before installing the TestRunner apk, we may repackage it.
if (installRunner) {
if (rebuildRunner) {
debug("REBUILDING " + testRunnerApk);
testRunnerApk = DUtilities.rebuildTestRunnerApk(testRunnerSourceDir, autApk, testRunnerApk, instrumentArg, true);
if (testRunnerApk==null) {
throw new RuntimeException(debugPrefix + " Fail to repackage the TestRunner apk!");
}
}
debug("INSTALLING " + testRunnerApk);
DUtilities.installReplaceAPK(testRunnerApk);
} else {
debug("BYPASSING INSTALLATION of Instrumentation Test Runner...");
}
// 2. Launch the InstrumentationTestRunner
if(!DUtilities.launchTestInstrumentation(instrumentArg)){
throw new RuntimeException("Fail to launch instrument '"+instrumentArg+"'");
}
// 3. Forward tcp port is needed? how to know the way of connection, by
// USB? by WIFI?
boolean portForwarding = true;
solo.setPortForwarding(portForwarding);
debug("Prepare for test successfully.");
}catch(RuntimeException e){
error("During preparation, met exception="+e.getMessage());
return false;
}
return true;
}
public boolean prepareDevice(){
// see if any devices is attached
boolean havedevice = false;
List<String> devices = null;
try{
devices = DUtilities.getAttachedDevices();
info("Detected "+ devices.size() +" device/emulators attached.");
if(devices.size() == 0){
DUtilities.DEFAULT_EMULATOR_AVD = avdSerialNo;
if((DUtilities.DEFAULT_EMULATOR_AVD != null) && (DUtilities.DEFAULT_EMULATOR_AVD.length()> 0)){
//DUtilities.killADBServer();
//try{Thread.sleep(5000);}catch(Exception x){}
info("Attempting to launch EMULATOR_AVD: "+ DUtilities.DEFAULT_EMULATOR_AVD);
if (! DUtilities.launchEmulatorAVD(DUtilities.DEFAULT_EMULATOR_AVD)){
String msg = "Unsuccessful launching EMULATOR_AVD: "+DUtilities.DEFAULT_EMULATOR_AVD +", or TIMEOUT was reached.";
debug(msg);
return false;
}else{
weLaunchedEmulator = true;
info("Emulator launch appears to be successful...");
havedevice = true;
if(unlockEmulatorScreen) {
String stat = DUtilities.unlockDeviceScreen()? " ":" NOT ";
info("Emulator screen was"+ stat +"successfully unlocked!");
}
}
}else{
String msg = "No Devices found and no EMULATOR_AVD specified in configuration file.";
debug(msg);
return false;
}
}else if(devices.size() > 1){
// if multiple device attached then user DeviceSerial to target device
DUtilities.DEFAULT_DEVICE_SERIAL = avdSerialNo;
if(DUtilities.DEFAULT_DEVICE_SERIAL.length() > 0){
boolean matched = false;
int d = 0;
String lcserial = DUtilities.DEFAULT_DEVICE_SERIAL.toLowerCase();
String lcdevice = null;
for(;(d < devices.size())&&(!matched);d++){
lcdevice = ((String)devices.get(d)).toLowerCase();
info("Attempting match device '"+ lcdevice +"' with default '"+ lcserial +"'");
matched = lcdevice.startsWith(lcserial);
}
// if DeviceSerial does not match one of multiple then abort
if(matched){
havedevice = true;
DUtilities.USE_DEVICE_SERIAL = " -s "+ DUtilities.DEFAULT_DEVICE_SERIAL +" ";
}else{
String msg = "Requested Device '"+ DUtilities.DEFAULT_DEVICE_SERIAL +"' was not found.";
debug(msg);
return false;
}
}else{
// if no DeviceSerial present then use first device
String device = null;
String tdev = (String)devices.get(0);
if(tdev.endsWith("device")){
device = tdev.substring(0, tdev.length() -6).trim();
}else if(tdev.endsWith("emulator")){// not known to be used
device = tdev.substring(0, tdev.length() -8).trim();
}else{
String msg = "Unknown Device Listing Format: "+ tdev;
debug(msg);
return false;
}
havedevice = true;
DUtilities.USE_DEVICE_SERIAL = " -s "+ device +" ";
}
}else{
// if one device, we don't need to specify -s DEVICE_SERIAL
// DUtilities.USE_DEVICE_SERIAL should already be empty ("");
havedevice = true;
}
}catch(Exception x){
debug("Aborting due to "+x.getClass().getSimpleName()+", "+ x.getMessage());
return false;
}
return havedevice;
}
/**
* Initialize the Solo object and launch the main application.<br>
* You will not modify this method in the sub-class, normally<br>
*
* @return true if the initialization is successful.
*/
final protected boolean initialize(){
boolean success = false;
try {
solo.initialize();
robotiumUtils = new RobotiumUtils(solo);
robotiumTimeout = new Timeout(solo);
//We can enable/disable the debug message of Protocol or Runner
solo.turnProtocolDebug(enableProtocolDebug);
solo.turnRunnerDebug(enableRunnerDebug);
//Start the main Activity
success = solo.startMainLauncher();
//Set the mainActivityUID
mainActivityUID = solo.getCurrentActivity();
debug("mainActivityUID="+mainActivityUID);
} catch (IllegalThreadStateException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (ShutdownInvocationException e) {
e.printStackTrace();
}
if(success){
debug("Launch application successfully.");
}else{
error("Fail to launch application.");
}
return success;
}
/**
* Terminate the remote engine.<br>
* Terminate the local controller runner.<br>
* Terminate the emulator if we have started it.<br>
*
* You will not modify this method in the sub-class.<br>
*
* @return true if the initialization is successful.
*/
final protected boolean terminate(){
boolean success = false;
robotiumUtils = null;
robotiumTimeout = null;
try {
if(!solo.shutdownRemote()){
warn("Fail to shutdown remote service.");
}
//Even if we fail to shutdown remote service, we will shutdown RemoteControlRunner
solo.shutdown();
if(!stopEmulator()){
warn("We fail to stop the emulator launched by us.");
}
success = true;
} catch (Exception e) {
e.printStackTrace();
}
if(success){
debug("terminate successfully.");
}else{
warn("Fail to terminate.");
}
return success;
}
/**
* Stop the emulator launched by us only if we have launched it and<br>
* we don't want to persist it.<br>
*
* @return boolean, true if the emulator is stopped successfully or we don't need to stop it.
*/
final protected boolean stopEmulator(){
boolean stopped = true;
if(weLaunchedEmulator){
//Then we will shutdown any emulator lauched by us.
if(!persistEmulators) {
info(" checking for launched emulators...");
stopped = DUtilities.shutdownLaunchedEmulators(weLaunchedEmulator);
}else{
info(" attempting to PERSIST any launched emulators...");
}
}else{
info("we didn't start any emulators.");
}
return stopped;
}
/**
* Use solo to test.<br>
* You will extend this method in the sub-class, normally<br>
*
* In the RobotiumTestRunner project, there is a file AndroidManifest.xml:<br>
* There is a tag <instrumentation> like following:
*
* <instrumentation android:name="com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner"
* android:targetPackage="com.android.example.spinner"
* android:label="General-Purpose Robotium Test Runner"/>
*
* If you want to test another application, you should modify the property "android:targetPackage"<br>
* For example, android:targetPackage="your.test.application.package"<br>
*
* And you need to override this method to do the test work.<br>
*/
protected void test(){
//Begin the testing
try {
String activityID = solo.getCurrentActivity();
Properties props = solo._last_remote_result;
String activityName = props.getProperty(Message.PARAM_NAME);
String activityClass = props.getProperty(Message.PARAM_CLASS);
info("CurrentActivity UID: "+ activityID);
info("CurrentActivity Class: "+ activityClass);
info("CurrentActivity Name: "+ activityName);
//DEBUG: Verifying the Name we return is the same one used by waitForActivity
if(solo.waitForActivity(activityName, 1000)){
pass("'"+activityName+"' was found in timeout period.");
}else{
warn("*** '"+activityName+"' was NOT FOUND in timeout period. ***");
}
// NEGATIVE TEST
if(solo.waitForActivity("BoguActivity", 1000)){
warn("*** BogusActivity was reported as found but is not a valid Activity! ***");
}else{
pass("BogusActivity was not found and was not expected to be found.");
}
String layoutUID = solo.getView("android.widget.LinearLayout", 0);
info("Layout UID= "+layoutUID);
String listUID = solo.getView("android.widget.ListView", 0);
info("list UID= "+listUID);
BufferedImage image = solo.takeScreenshot("ActivityScreenshot");
if(image != null) {
info("Screenshot image width:"+ image.getWidth());
info("Screenshot image height:"+ image.getHeight());
info("Screenshot stored at: "+ solo._last_remote_result.getProperty(Message.PARAM_NAME+"FILE"));
}
else info("Screenshot returned as NULL!");
// SHUTDOWN all Activities. Done Testing.
if(solo.finishOpenedActivities()){
info("Application finished/shutdown without error.");
}else{
warn("Application finished/shutdown with error.");
}
} catch (IllegalThreadStateException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (ShutdownInvocationException e) {
e.printStackTrace();
} catch (RemoteSoloException e) {
e.printStackTrace();
}
}
public void debug(String message) {
System.out.println("SoloTest DEBUG: "+message);
}
public void info(String message) {
System.out.println("SoloTest INFO: "+message);
}
public void warn(String message) {
System.err.println("SoloTest WARN: "+message);
}
public void pass(String message) {
System.out.println("SoloTest PASS: "+message);
}
public void fail( String message) {
System.err.println("SoloTest FAIL: "+message);
}
public void error( String message) {
System.err.println("SoloTest ERROR: "+message);
}
/**
* @param viewUID
* @throws Exception
*/
protected void goBackToViewUID(String viewUID) throws Exception{
int loopLimit = 10;
int looptime = 0;
do{
if(solo.waitForViewUID(viewUID, 50, true)){
debug("Back to view "+viewUID);
return;
}else{
//solo.getCurrentActivity() will never return null? There is always an activity.
String currentActivity = solo.getCurrentActivity();
debug("Current Activity is "+currentActivity);
if(currentActivity==null || currentActivity.equals(mainActivityUID)){
debug("Exit the main activity!!!");
break;
}else{
debug("Trying go back...");
}
}
looptime++;
}while((looptime<loopLimit) && solo.goBack());
debug("Can not go back to view "+viewUID);
}
protected void pause(int millis){
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected void scrollToTop(){
//scroll to the top of the list
try {
while(solo.scrollUp()){
debug("Scrolling up......");
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected void scrollToBottoum(){
//scroll to the bottom of the list
try {
while(solo.scrollDown()){
debug("Scrolling down......");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Wrap the text with regex prefix and suffix ".*"<br>
* When you call some method like {@link Solo#clickOnText(String)}, the parameter<br>
* can be regex string to match more, you can call this method to wrap the parameter.<br>
*
* @param text String
* @return String, .*text.*
*/
protected String wrapRegex(String text){
if(text==null) return text;
return ".*"+text+".*";
}
/**
* @param args Array of String passed from command line:
* messenger=xxx
* runner=xxx
* runnersource=xxx
* instrument=xxx
*/
public static void main(String[] args){
SoloTest soloTest = new SoloTest(args);
// soloTest.installAUT = false;
// soloTest.installMessenger = false;
// soloTest.installRunner = false;
//You can turn on the debug log to see the 'debug message' from protocol or runner
// soloTest.setProtocolDebug(true);
// soloTest.setRunnerDebug(true);
// soloTest.setRebuildRunner(true);
soloTest.process();
}
}