How to use this.uiAutomator.start method in Appium Android Driver

Best JavaScript code snippet using appium-android-driver

Run Appium Android Driver automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

android.js

Source: android.js Github

copy
1"use strict";
2
3var errors = require('../../server/errors.js')
4  , path = require('path')
5  , fs = require('fs')
6  , Device = require('../device.js')
7  , _ = require('underscore')
8  , logger = require('../../server/logger.js').get('appium')
9  , deviceCommon = require('../common.js')
10  , status = require("../../server/status.js")
11  , async = require('async')
12  , androidController = require('./android-controller.js')
13  , androidContextController = require('./android-context-controller.js')
14  , androidCommon = require('./android-common.js')
15  , androidHybrid = require('./android-hybrid.js')
16  , UiAutomator = require('./uiautomator.js')
17  , UnknownError = errors.UnknownError;
18
19var Android = function () {
20  this.init();
21};
22
23_.extend(Android.prototype, Device.prototype);
24
25Android.prototype._deviceInit = Device.prototype.init;
26Android.prototype.init = function () {
27  this._deviceInit();
28  this.appExt = ".apk";
29  this.capabilities = {
30    platform: 'LINUX'
31  , browserName: 'Android'
32  , platformVersion: '4.1'
33  , webStorageEnabled: false
34  , takesScreenshot: true
35  , javascriptEnabled: true
36  , databaseEnabled: false
37  , networkConnectionEnabled: true
38  , locationContextEnabled: false
39  };
40  this.args.devicePort = 4724;
41  this.appMd5Hash = null;
42  this.args.avd = null;
43  this.args.language = null;
44  this.args.locale = null;
45  this.args.javaVersion = null;
46  this.initQueue();
47  this.implicitWaitMs = 0;
48  this.shuttingDown = false;
49  this.adb = null;
50  this.uiautomator = null;
51  this.uiautomatorRestartOnExit = false;
52  this.uiautomatorIgnoreExit = false;
53  this.swipeStepsPerSec = 28;
54  this.dragStepsPerSec = 40;
55  this.asyncWaitMs = 0;
56  this.remote = null;
57  this.contexts = [];
58  this.curContext = this.defaultContext();
59  this.didLaunch = false;
60  this.launchCb = function () {};
61  this.uiautomatorExitCb = function () {};
62  this.dataDir = null;
63  this.isProxy = false;
64  this.proxyHost = null;
65  this.proxyPort = null;
66  this.proxySessionId = null;
67  this.avoidProxy = [
68    ['POST', new RegExp('^/wd/hub/session/[^/]+/context')]
69  , ['GET', new RegExp('^/wd/hub/session/[^/]+/context')]
70  , ['GET', new RegExp('^/wd/hub/session/[^/]+/contexts')]
71  , ['POST', new RegExp('^/wd/hub/session/[^/]+/appium')]
72  , ['GET', new RegExp('^/wd/hub/session/[^/]+/appium')]
73  ];
74
75  // listen for changes to ignoreUnimportantViews
76  this.settings.on("update", function (update) {
77    if (update.key === "ignoreUnimportantViews") {
78      this.setCompressedLayoutHierarchy(update.value, update.callback);
79    } else {
80      update.callback();
81    }
82  }.bind(this));
83};
84
85Android.prototype._deviceConfigure = Device.prototype.configure;
86
87Android.prototype.noLaunchSetup = function (cb) {
88  logger.debug("Setting up Android for 'autoLaunch: false'");
89  async.series([
90    this.initJavaVersion.bind(this),
91    this.initAdb.bind(this),
92  ], function (err) { cb(err); });
93};
94
95Android.prototype.start = function (cb, onDie) {
96  this.launchCb = cb;
97  this.uiautomatorExitCb = onDie;
98  logger.info("Starting android appium");
99  async.series([
100    this.initJavaVersion.bind(this),
101    this.initAdb.bind(this),
102    this.packageAndLaunchActivityFromManifest.bind(this),
103    this.initUiautomator.bind(this),
104    this.initChromedriverPath.bind(this),
105    this.prepareDevice.bind(this),
106    this.checkApiLevel.bind(this),
107    this.pushStrings.bind(this),
108    this.processFromManifest.bind(this),
109    this.uninstallApp.bind(this),
110    this.installAppForTest.bind(this),
111    this.forwardPort.bind(this),
112    this.pushAppium.bind(this),
113    this.initUnicode.bind(this),
114    this.pushSettingsApp.bind(this),
115    this.pushUnlock.bind(this),
116    function (cb) {this.uiautomator.start(cb);}.bind(this),
117    this.wakeUp.bind(this),
118    this.unlock.bind(this),
119    this.getDataDir.bind(this),
120    this.setupCompressedLayoutHierarchy.bind(this),
121    this.startAppUnderTest.bind(this),
122    this.initAutoWebview.bind(this),
123    this.setActualCapabilities.bind(this)
124  ], function (err) {
125    if (err) {
126      this.shutdown(function () {
127        this.launchCb(err);
128      }.bind(this));
129    } else {
130      this.didLaunch = true;
131      this.launchCb(null, this.proxySessionId);
132    }
133  }.bind(this));
134};
135
136Android.prototype.initUiautomator = function (cb) {
137  if (this.uiautomator === null) {
138    this.uiautomator = new UiAutomator(this.adb, this.args);
139    this.uiautomator.setExitHandler(this.onUiautomatorExit.bind(this));
140  }
141  return cb();
142};
143
144Android.prototype.onLaunch = function (err) {
145  var readyToGo = function () {
146    this.didLaunch = true;
147    this.launchCb();
148  }.bind(this);
149
150  var giveUp = function (err) {
151    this.shutdown(function () {
152      this.launchCb(err);
153    }.bind(this));
154  }.bind(this);
155
156  if (err) {
157    if (this.checkShouldRelaunch(err)) {
158      logger.error(err);
159      logger.error("Above error isn't fatal, maybe relaunching adb will help....");
160      this.adb.waitForDevice(function (err) {
161        if (err) return giveUp(err);
162        readyToGo();
163      });
164    } else {
165      giveUp(err);
166    }
167  } else {
168    readyToGo();
169  }
170};
171
172Android.prototype.restartUiautomator = function (cb) {
173  async.series([
174    this.forwardPort.bind(this)
175    , this.uiautomator.start.bind(this.uiautomator)
176    , this.setupCompressedLayoutHierarchy.bind(this)
177  ], cb);
178};
179
180/*
181 * Execute an arbitrary function and handle potential ADB disconnection before
182 * proceeding
183 */
184Android.prototype.wrapActionAndHandleADBDisconnect = function (action, ocb) {
185  async.series([
186    function (cb) {
187      this.uiautomatorIgnoreExit = true;
188      action(cb);
189    }.bind(this)
190    , this.adb.restart.bind(this.adb)
191    , this.restartUiautomator.bind(this)
192  ], function (err) {
193    this.uiautomatorIgnoreExit = false;
194    ocb(err);
195  }.bind(this));
196};
197
198Android.prototype.onUiautomatorExit = function () {
199  logger.debug("UiAutomator exited");
200  var respondToClient = function () {
201    this.stopChromedriverProxies(function () {
202      this.cleanup();
203      if (!this.didLaunch) {
204        var msg = "UiAutomator quit before it successfully launched";
205        logger.error(msg);
206        this.launchCb(new Error(msg));
207        return;
208      } else if (typeof this.cbForCurrentCmd === "function") {
209        var error = new UnknownError("UiAutomator died while responding to " +
210                                      "command, please check appium logs!");
211        this.cbForCurrentCmd(error, null);
212      }
213      // make sure appium.js knows we crashed so it can clean up
214      this.uiautomatorExitCb();
215    }.bind(this));
216  }.bind(this);
217
218  if (this.adb) {
219    var uninstall = function () {
220      logger.debug("Attempting to uninstall app");
221      this.uninstallApp(function () {
222        this.shuttingDown = false;
223        respondToClient();
224      }.bind(this));
225    }.bind(this);
226
227    if (!this.uiautomatorIgnoreExit) {
228      this.adb.ping(function (err, ok) {
229        if (ok) {
230          uninstall();
231        } else {
232          logger.debug(err);
233          this.adb.restart(function (err) {
234            if (err) {
235              logger.debug(err);
236            }
237            if (this.uiautomatorRestartOnExit) {
238              this.uiautomatorRestartOnExit = false;
239              this.restartUiautomator(function (err) {
240                if (err) {
241                  logger.debug(err);
242                  uninstall();
243                }
244              }.bind(this));
245            } else {
246              uninstall();
247            }
248          }.bind(this));
249        }
250      }.bind(this));
251    } else {
252      this.uiautomatorIgnoreExit = false;
253    }
254  } else {
255    logger.debug("We're in uiautomator's exit callback but adb is gone already");
256    respondToClient();
257  }
258};
259
260Android.prototype.checkShouldRelaunch = function (launchErr) {
261  if (launchErr.message === null || typeof launchErr.message === 'undefined') {
262    logger.error("We're checking if we should relaunch based on something " +
263                 "which isn't an error object. Check the codez!");
264    return false;
265  }
266  var msg = launchErr.message.toString();
267  var relaunchOn = [
268    'Could not find a connected Android device'
269    , 'Device did not become ready'
270  ];
271  var relaunch = false;
272  _.each(relaunchOn, function (relaunchMsg) {
273    relaunch = relaunch || msg.indexOf(relaunchMsg) !== -1;
274  });
275  return relaunch;
276};
277
278Android.prototype.checkApiLevel = function (cb) {
279  this.adb.getApiLevel(function (err, apiLevel) {
280    if (err) return cb(err);
281    logger.info('Device API level is:', parseInt(apiLevel, 10));
282    if (parseInt(apiLevel) < 17) {
283      var msg = "Android devices must be of API level 17 or higher. Please change your device to Selendroid or upgrade Android on your device.";
284      logger.error(msg); // logs the error when we encounter it
285      return cb(new Error(msg)); // send the error up the chain
286    }
287
288    cb();
289  });
290};
291
292Android.prototype.decorateChromeOptions = function (caps) {
293  // add options from appium session caps
294  if (this.args.chromeOptions) {
295    _.each(this.args.chromeOptions, function (val, option) {
296      if (typeof caps.chromeOptions[option] === "undefined") {
297        caps.chromeOptions[option] = val;
298      } else {
299        logger.warn("Cannot pass option " + caps.chromeOptions[option] + " because Appium needs it to make chromeDriver work");
300      }
301    });
302  }
303
304  // add device id from adb
305  caps.chromeOptions.androidDeviceSerial = this.adb.curDeviceId;
306
307  return caps;
308};
309
310Android.prototype.processFromManifest = function (cb) {
311  if (!this.args.app) {
312    return cb();
313  } else { // apk must be local to process the manifest.
314    this.adb.processFromManifest(this.args.app, function (err, process) {
315      var value = process || this.args.appPackage;
316
317      this.appProcess = value;
318      logger.debug("Set app process to: " + this.appProcess);
319
320      cb();
321    }.bind(this));
322  }
323};
324
325Android.prototype.pushStrings = function (cb, language) {
326  var outputPath = path.resolve(this.args.tmpDir, this.args.appPackage);
327  var remotePath = '/data/local/tmp';
328  var stringsJson = 'strings.json';
329  this.extractStrings(function (err) {
330    if (err) {
331      if (!fs.existsSync(this.args.app)) {
332        // apk doesn't exist locally so remove old strings.json
333        return this.adb.rimraf(remotePath + '/' + stringsJson, function (err) {
334          if (err) return cb(new Error("Could not remove old strings"));
335          cb();
336        });
337      } else {
338        // if we can't get strings, just dump an empty json and continue
339        var remoteFile = remotePath + '/' + stringsJson;
340        return this.adb.shell("echo '{}' > " + remoteFile, cb);
341      }
342    }
343    var jsonFile = path.resolve(outputPath, stringsJson);
344    this.adb.push(jsonFile, remotePath, function (err) {
345      if (err) return cb(new Error("Could not push strings.json"));
346      cb();
347    });
348  }.bind(this), language);
349};
350
351Android.prototype.getStrings = function (language, stringFile, cb) {
352  if (this.language && this.language === language) {
353    // Return last strings
354    return cb(null, {
355      status: status.codes.Success.code,
356      value: this.apkStrings
357    });
358  }
359
360  // Extract, push and return strings
361  return this.pushStrings(function () {
362    this.proxy(["updateStrings", {}], function (err, res) {
363      if (err || res.status !== status.codes.Success.code) return cb(err, res);
364      cb(null, {
365        status: status.codes.Success.code,
366        value: this.apkStrings
367      });
368    }.bind(this));
369  }.bind(this), language);
370};
371
372Android.prototype.pushAppium = function (cb) {
373  logger.debug("Pushing appium bootstrap to device...");
374  var binPath = path.resolve(__dirname, "..", "..", "..", "build",
375      "android_bootstrap", "AppiumBootstrap.jar");
376  fs.stat(binPath, function (err) {
377    if (err) {
378      cb(new Error("Could not find AppiumBootstrap.jar; please run " +
379                   "'grunt buildAndroidBootstrap'"));
380    } else {
381      this.adb.push(binPath, this.remoteTempPath(), cb);
382    }
383  }.bind(this));
384};
385
386Android.prototype.startAppUnderTest = function (cb) {
387  this.startApp(this.args, cb);
388};
389
390Android.prototype.startApp = function (args, cb) {
391  if (args.androidCoverage) {
392    this.adb.androidCoverage(args.androidCoverage, args.appWaitPackage,
393      args.appWaitActivity, cb);
394  } else {
395    this.adb.startApp({
396      pkg: args.appPackage,
397      activity: args.appActivity,
398      action: args.intentAction,
399      category: args.intentCategory,
400      flags: args.intentFlags,
401      waitPkg: args.appWaitPackage,
402      waitActivity: args.appWaitActivity,
403      optionalIntentArguments: args.optionalIntentArguments,
404      stopApp: args.stopAppOnReset
405    }, cb);
406  }
407};
408
409Android.prototype.stop = function (cb) {
410  if (this.shuttingDown) {
411    logger.debug("Already in process of shutting down.");
412    return cb();
413  }
414  this.shuttingDown = true;
415
416  var completeShutdown = function (cb) {
417    if (this.adb) {
418      this.adb.goToHome(function () {
419        this.shutdown(cb);
420      }.bind(this));
421    } else {
422      this.shutdown(cb);
423    }
424  }.bind(this);
425
426  if (this.args.fullReset) {
427    logger.debug("Removing app from device");
428    this.uninstallApp(function (err) {
429      if (err) {
430        // simply warn on error here, because we don't want to stop the shutdown
431        // process
432        logger.warn(err);
433      }
434      completeShutdown(cb);
435    });
436  } else {
437    completeShutdown(cb);
438  }
439
440
441};
442
443Android.prototype.cleanup = function () {
444  logger.debug("Cleaning up android objects");
445  this.adb = null;
446  this.uiautomator = null;
447  this.shuttingDown = false;
448};
449
450Android.prototype.shutdown = function (cb) {
451  var next = function () {
452    this.stopChromedriverProxies(function () {
453      if (this.uiautomator) {
454        this.uiautomator.shutdown(function () {
455          this.cleanup();
456          cb();
457        }.bind(this));
458      } else {
459        this.cleanup();
460        cb();
461      }
462    }.bind(this));
463  }.bind(this);
464
465  if (this.adb) {
466    this.adb.endAndroidCoverage();
467    if (this.args.unicodeKeyboard && this.args.resetKeyboard && this.defaultIME) {
468      logger.debug('Resetting IME to \'' + this.defaultIME + '\'');
469      this.adb.setIME(this.defaultIME, function (err) {
470        if (err) {
471          // simply warn on error here, because we don't want to stop the shutdown
472          // process
473          logger.warn(err);
474        }
475        if (this.adb) {
476          this.adb.stopLogcat(function () {
477            next();
478          }.bind(this));
479        }
480      }.bind(this));
481    } else {
482      this.adb.stopLogcat(function () {
483        next();
484      }.bind(this));
485    }
486  } else {
487    next();
488  }
489};
490
491Android.prototype.proxy = deviceCommon.proxy;
492Android.prototype.respond = deviceCommon.respond;
493
494Android.prototype.initQueue = function () {
495  this.queue = async.queue(function (task, cb) {
496    var action = task.action,
497        params = task.params;
498
499    this.cbForCurrentCmd = cb;
500
501    if (this.adb && !this.shuttingDown) {
502      this.uiautomator.sendAction(action, params, function (response) {
503        this.cbForCurrentCmd = null;
504        if (typeof cb === 'function') {
505          this.respond(response, cb);
506        }
507      }.bind(this));
508    } else {
509      this.cbForCurrentCmd = null;
510      var msg = "Tried to send command to non-existent Android device, " +
511                 "maybe it shut down?";
512      if (this.shuttingDown) {
513        msg = "We're in the middle of shutting down the Android device, " +
514              "so your request won't be executed. Sorry!";
515      }
516      this.respond({
517        status: status.codes.UnknownError.code
518      , value: msg
519      }, cb);
520    }
521  }.bind(this), 1);
522};
523
524Android.prototype.push = function (elem) {
525  this.queue.push({action: elem[0][0], params: elem[0][1] || {}}, elem[1]);
526};
527
528Android.prototype.wakeUp = function (cb) {
529  // requires an appium bootstrap connection loaded
530  logger.debug("Waking up device if it's not alive");
531  this.proxy(["wake", {}], cb);
532};
533
534Android.prototype.getDataDir = function (cb) {
535  this.proxy(["getDataDir", {}], function (err, res) {
536    if (err) return cb(err);
537    this.dataDir = res.value;
538    logger.debug("dataDir set to: " + this.dataDir);
539    cb();
540  }.bind(this));
541};
542
543// Set CompressedLayoutHierarchy on the device based on current settings object
544Android.prototype.setupCompressedLayoutHierarchy = function (cb) {
545
546  // setup using cap
547  if (_.has(this.args, 'ignoreUnimportantViews')) {
548    // set the setting directly on the internal _settings object, this way we don't trigger an update event
549    this.settings._settings.ignoreUnimportantViews = this.args.ignoreUnimportantViews;
550  }
551
552  if (_.isUndefined(this.getSetting("ignoreUnimportantViews"))) {
553    return cb();
554  }
555  this.setCompressedLayoutHierarchy(this.getSetting("ignoreUnimportantViews"), cb);
556};
557
558// Set CompressedLayoutHierarchy on the device
559Android.prototype.setCompressedLayoutHierarchy = function (compress, cb) {
560  this.proxy(["compressedLayoutHierarchy", {compressLayout: compress}], cb);
561};
562
563Android.prototype.waitForActivityToStop = function (cb) {
564  this.adb.waitForNotActivity(this.args.appWaitPackage, this.args.appWaitActivity, cb);
565};
566
567Android.prototype.setActualCapabilities = function (cb) {
568  this.capabilities.deviceName = this.adb.udid || this.adb.curDeviceId;
569  this.adb.shell("getprop ro.build.version.release", function (err, version) {
570    if (err) {
571      logger.warn(err);
572    } else {
573      logger.debug("Device is at release version " + version);
574      this.capabilities.platformVersion = version;
575    }
576  }.bind(this));
577  cb();
578};
579
580Android.prototype.resetTimeout = deviceCommon.resetTimeout;
581Android.prototype.waitForCondition = deviceCommon.waitForCondition;
582Android.prototype.implicitWaitForCondition = deviceCommon.implicitWaitForCondition;
583Android.prototype.getSettings = deviceCommon.getSettings;
584Android.prototype.updateSettings = deviceCommon.updateSettings;
585
586_.extend(Android.prototype, androidController);
587_.extend(Android.prototype, androidContextController);
588_.extend(Android.prototype, androidCommon);
589_.extend(Android.prototype, androidHybrid);
590
591module.exports = Android;
592
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Appium Android Driver on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)