mirror of
https://github.com/appium/appium.git
synced 2026-04-27 13:59:33 -05:00
Merge pull request #668 from bootstraponline/find_by_id
Add find element by id for Android
This commit is contained in:
+52
-10
@@ -396,19 +396,41 @@ ADB.prototype.prepareDevice = function(onReady) {
|
||||
], onReady);
|
||||
};
|
||||
|
||||
ADB.prototype.pushStrings = function(cb) {
|
||||
var me = this;
|
||||
var stringsFromApkJarPath = path.resolve(__dirname, '../app/android/strings_from_apk.jar');
|
||||
var outputPath = path.resolve(getTempPath(), me.appPackage);
|
||||
var makeStrings = ['java -jar ', stringsFromApkJarPath,
|
||||
' ', me.apkPath, ' ', outputPath].join('');
|
||||
logger.debug(makeStrings);
|
||||
exec(makeStrings, {}, function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
logger.debug(stderr);
|
||||
return cb("error making strings");
|
||||
}
|
||||
var jsonFile = path.resolve(outputPath, 'strings.json');
|
||||
var remotePath = "/data/local/tmp";
|
||||
var pushCmd = me.adbCmd + " push " + jsonFile + " " + remotePath;
|
||||
exec(pushCmd, {}, function(err, stdout, stderr) {
|
||||
cb(null);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ADB.prototype.startAppium = function(onReady, onExit) {
|
||||
logger.info("Starting android appium");
|
||||
var me = this
|
||||
, doRun = function(err) {
|
||||
if (err) return onReady(err);
|
||||
me.runBootstrap(onReady, onExit);
|
||||
};
|
||||
if (err) return onReady(err);
|
||||
me.runBootstrap(onReady, onExit);
|
||||
};
|
||||
this.onExit = onExit;
|
||||
|
||||
logger.debug("Using fast reset? " + this.fastReset);
|
||||
|
||||
async.series([
|
||||
function(cb) { me.prepareDevice(cb); },
|
||||
function(cb) { me.pushStrings(cb); },
|
||||
function(cb) { me.installApp(cb); },
|
||||
function(cb) { me.forwardPort(cb); },
|
||||
function(cb) { me.pushAppium(cb); },
|
||||
@@ -701,11 +723,9 @@ ADB.prototype.runBootstrap = function(readyCb, exitCb) {
|
||||
// The bootstrap jar has crashed so it must be restarted.
|
||||
this.restartBootstrap = false;
|
||||
me.runBootstrap(function() {
|
||||
readyCb(null, function() {
|
||||
// Resend last command because the client is still waiting for the
|
||||
// response.
|
||||
me.android.push(null, true);
|
||||
});
|
||||
// Resend last command because the client is still waiting for the
|
||||
// response.
|
||||
me.android.push(null, true);
|
||||
}, exitCb);
|
||||
return;
|
||||
}
|
||||
@@ -761,7 +781,25 @@ ADB.prototype.sendAutomatorCommand = function(action, params, cb) {
|
||||
};
|
||||
|
||||
ADB.prototype.sendCommand = function(type, extra, cb) {
|
||||
if (this.socketClient) {
|
||||
if (this.cmdCb !== null) {
|
||||
logger.warn("Trying to run a command when one is already in progress. " +
|
||||
"Will spin a bit and try again");
|
||||
var me = this;
|
||||
var start = Date.now();
|
||||
var timeoutMs = 10000;
|
||||
var intMs = 200;
|
||||
var waitForCmdCbNull = function() {
|
||||
if (me.cmdCb === null) {
|
||||
me.sendCommand(type, extra, cb);
|
||||
} else if ((Date.now() - start) < timeoutMs) {
|
||||
setTimeout(waitForCmdCbNull, intMs);
|
||||
} else {
|
||||
cb(new Error("Never became able to push strings since a command " +
|
||||
"was in process"));
|
||||
}
|
||||
};
|
||||
waitForCmdCbNull();
|
||||
} else if (this.socketClient) {
|
||||
if (typeof extra === "undefined" || extra === null) {
|
||||
extra = {};
|
||||
}
|
||||
@@ -769,7 +807,11 @@ ADB.prototype.sendCommand = function(type, extra, cb) {
|
||||
cmd = _.extend(cmd, extra);
|
||||
var cmdJson = JSON.stringify(cmd) + "\n";
|
||||
this.cmdCb = cb;
|
||||
this.debug("Sending command to android: " + cmdJson.trim());
|
||||
var logCmd = cmdJson.trim();
|
||||
if (logCmd.length > 1000) {
|
||||
logCmd = logCmd.substr(0, 1000) + "...";
|
||||
}
|
||||
this.debug("Sending command to android: " + logCmd);
|
||||
this.socketClient.write(cmdJson);
|
||||
} else {
|
||||
cb({
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
package io.appium.android.bootstrap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import io.appium.android.bootstrap.exceptions.AndroidCommandException;
|
||||
import io.appium.android.bootstrap.exceptions.CommandTypeException;
|
||||
import io.appium.android.bootstrap.exceptions.SocketServerException;
|
||||
import io.appium.android.bootstrap.handler.Find;
|
||||
import io.appium.android.bootstrap.utils.TheWatchers;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import io.appium.android.bootstrap.exceptions.AndroidCommandException;
|
||||
import io.appium.android.bootstrap.exceptions.CommandTypeException;
|
||||
import io.appium.android.bootstrap.exceptions.SocketServerException;
|
||||
import io.appium.android.bootstrap.utils.TheWatchers;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* The SocketServer class listens on a specific port for commands from Appium,
|
||||
@@ -27,7 +34,8 @@ class SocketServer {
|
||||
PrintWriter out;
|
||||
boolean keepListening;
|
||||
private final AndroidCommandExecutor executor;
|
||||
private final TheWatchers watchers = TheWatchers.getInstance();
|
||||
private final TheWatchers watchers = TheWatchers.getInstance();
|
||||
private final Timer timer = new Timer("WatchTimer");
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -45,6 +53,7 @@ class SocketServer {
|
||||
throw new SocketServerException(
|
||||
"Could not start socket server listening on " + port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,17 +113,22 @@ class SocketServer {
|
||||
*/
|
||||
public void listenForever() throws SocketServerException {
|
||||
Logger.info("Appium Socket Server Ready");
|
||||
loadStringsJson();
|
||||
final TimerTask updateWatchers = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
watchers.check();
|
||||
}
|
||||
};
|
||||
timer.scheduleAtFixedRate(updateWatchers, 100, 100);
|
||||
|
||||
try {
|
||||
client = server.accept();
|
||||
Logger.info("Client connected");
|
||||
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
||||
out = new PrintWriter(client.getOutputStream(), true);
|
||||
while (keepListening) {
|
||||
if (in.ready()) {
|
||||
handleClientData();
|
||||
}
|
||||
Thread.sleep(100);
|
||||
watchers.check();
|
||||
handleClientData();
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
@@ -122,8 +136,24 @@ class SocketServer {
|
||||
Logger.info("Closed client connection");
|
||||
} catch (final IOException e) {
|
||||
throw new SocketServerException("Error when client was trying to connect");
|
||||
} catch (InterruptedException e) {
|
||||
throw new SocketServerException("The socket server was interupted");
|
||||
}
|
||||
}
|
||||
|
||||
public void loadStringsJson() {
|
||||
Logger.info("Loading json...");
|
||||
try {
|
||||
final File jsonFile = new File("/data/local/tmp/strings.json");
|
||||
final DataInputStream dataInput = new DataInputStream(
|
||||
new FileInputStream(jsonFile));
|
||||
final byte[] jsonBytes = new byte[(int) jsonFile.length()];
|
||||
dataInput.readFully(jsonBytes);
|
||||
// this closes FileInputStream
|
||||
dataInput.close();
|
||||
final String jsonString = new String(jsonBytes, "UTF-8");
|
||||
Find.apkStrings = new JSONObject(jsonString);
|
||||
Logger.info("json loading complete.");
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +161,8 @@ class SocketServer {
|
||||
* When {@link #handleClientData()} has valid data, this method delegates the
|
||||
* command.
|
||||
*
|
||||
* @param cmd AndroidCommand
|
||||
* @param cmd
|
||||
* AndroidCommand
|
||||
* @return Result
|
||||
*/
|
||||
private String runCommand(final AndroidCommand cmd) {
|
||||
|
||||
@@ -16,6 +16,8 @@ import io.appium.android.bootstrap.exceptions.InvalidStrategyException;
|
||||
import io.appium.android.bootstrap.exceptions.UnallowedTagNameException;
|
||||
import io.appium.android.bootstrap.selector.Strategy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
@@ -37,8 +39,9 @@ import com.android.uiautomator.core.UiSelector;
|
||||
*
|
||||
*/
|
||||
public class Find extends CommandHandler {
|
||||
AndroidElementsHash elements = AndroidElementsHash.getInstance();
|
||||
Dynamic dynamic = new Dynamic();
|
||||
AndroidElementsHash elements = AndroidElementsHash.getInstance();
|
||||
Dynamic dynamic = new Dynamic();
|
||||
public static JSONObject apkStrings = null;
|
||||
|
||||
private Object[] cascadeChildSels(final ArrayList<UiSelector> tail,
|
||||
final ArrayList<String> tailOuts) {
|
||||
@@ -324,8 +327,8 @@ public class Find extends CommandHandler {
|
||||
* @throws InvalidStrategyException
|
||||
* @throws AndroidCommandException
|
||||
*/
|
||||
private List<UiSelector> getSelector(final Strategy strategy,
|
||||
final String text, final Boolean many) throws InvalidStrategyException,
|
||||
private List<UiSelector> getSelector(final Strategy strategy, String text,
|
||||
final Boolean many) throws InvalidStrategyException,
|
||||
AndroidCommandException, UnallowedTagNameException {
|
||||
final List<UiSelector> selectors = new ArrayList<UiSelector>();
|
||||
UiSelector sel = new UiSelector();
|
||||
@@ -349,6 +352,19 @@ public class Find extends CommandHandler {
|
||||
selectors.add(sel2);
|
||||
}
|
||||
break;
|
||||
case ID:
|
||||
try {
|
||||
text = apkStrings.getString(text);
|
||||
Logger.debug("Searching for text: " + text);
|
||||
} catch (final Exception e) { // JSONException and NullPointerException
|
||||
|
||||
final StringWriter string = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(string));
|
||||
|
||||
throw new InvalidStrategyException("Unable to search by ID for "
|
||||
+ text + ".\n" + string.toString());
|
||||
}
|
||||
// now fall through and do a name search
|
||||
case NAME:
|
||||
sel = sel.description(text);
|
||||
if (!many) {
|
||||
@@ -367,7 +383,6 @@ public class Find extends CommandHandler {
|
||||
break;
|
||||
case LINK_TEXT:
|
||||
case PARTIAL_LINK_TEXT:
|
||||
case ID:
|
||||
case CSS_SELECTOR:
|
||||
default:
|
||||
throw new InvalidStrategyException("Strategy "
|
||||
|
||||
@@ -7,38 +7,26 @@ import io.appium.android.bootstrap.Logger;
|
||||
|
||||
public class TheWatchers {
|
||||
private static TheWatchers ourInstance = new TheWatchers();
|
||||
private long start = System.currentTimeMillis();
|
||||
private long delta = 1;
|
||||
private boolean alerted = false;
|
||||
|
||||
public static TheWatchers getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private TheWatchers() {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void setDelta(long seconds) {
|
||||
delta = seconds * 1000;
|
||||
}
|
||||
private TheWatchers() { }
|
||||
|
||||
public boolean check() {
|
||||
if(start + delta < System.currentTimeMillis()) {
|
||||
// Send only one alert message...
|
||||
if (isDialogPresent() && (!alerted)) {
|
||||
Logger.info("Emitting system alert message");
|
||||
alerted = true;
|
||||
}
|
||||
|
||||
// if the dialog went away, make sure we can send an alert again
|
||||
if (!isDialogPresent() && alerted) {
|
||||
alerted = false;
|
||||
}
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
// Send only one alert message...
|
||||
if (isDialogPresent() && (!alerted)) {
|
||||
Logger.info("Emitting system alert message");
|
||||
alerted = true;
|
||||
}
|
||||
return false;
|
||||
|
||||
// if the dialog went away, make sure we can send an alert again
|
||||
if (!isDialogPresent() && alerted) {
|
||||
alerted = false;
|
||||
}
|
||||
return alerted;
|
||||
}
|
||||
|
||||
public boolean isDialogPresent() {
|
||||
|
||||
+1
-1
@@ -792,4 +792,4 @@ Android.prototype.getCurrentActivity = function(cb) {
|
||||
|
||||
module.exports = function(opts) {
|
||||
return new Android(opts);
|
||||
};
|
||||
};
|
||||
Binary file not shown.
Reference in New Issue
Block a user