PageRenderTime 60ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/pushWithPythonServer/pushnotification/platforms/android/cordova/lib/emulator.js

https://gitlab.com/bsan/ionicDev
JavaScript | 328 lines | 235 code | 19 blank | 74 comment | 39 complexity | e8385abc8fc577be7302ff72dcd79419 MD5 | raw file
  1. #!/usr/bin/env node
  2. /*
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing,
  12. software distributed under the License is distributed on an
  13. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. KIND, either express or implied. See the License for the
  15. specific language governing permissions and limitations
  16. under the License.
  17. */
  18. var shell = require('shelljs'),
  19. exec = require('./exec'),
  20. Q = require('q'),
  21. path = require('path'),
  22. appinfo = require('./appinfo'),
  23. build = require('./build'),
  24. ROOT = path.join(__dirname, '..', '..'),
  25. child_process = require('child_process'),
  26. new_emulator = 'cordova_emulator';
  27. /**
  28. * Returns a Promise for a list of emulator images in the form of objects
  29. * {
  30. name : <emulator_name>,
  31. path : <path_to_emulator_image>,
  32. target : <api_target>,
  33. abi : <cpu>,
  34. skin : <skin>
  35. }
  36. */
  37. module.exports.list_images = function() {
  38. return exec('android list avds')
  39. .then(function(output) {
  40. var response = output.split('\n');
  41. var emulator_list = [];
  42. for (var i = 1; i < response.length; i++) {
  43. // To return more detailed information use img_obj
  44. var img_obj = {};
  45. if (response[i].match(/Name:\s/)) {
  46. img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
  47. if (response[i + 1].match(/Path:\s/)) {
  48. i++;
  49. img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
  50. }
  51. if (response[i + 1].match(/\(API\slevel\s/)) {
  52. i++;
  53. img_obj['target'] = response[i].replace('\r', '');
  54. }
  55. if (response[i + 1].match(/ABI:\s/)) {
  56. i++;
  57. img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
  58. }
  59. if (response[i + 1].match(/Skin:\s/)) {
  60. i++;
  61. img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
  62. }
  63. emulator_list.push(img_obj);
  64. }
  65. /* To just return a list of names use this
  66. if (response[i].match(/Name:\s/)) {
  67. emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
  68. }*/
  69. }
  70. return emulator_list;
  71. });
  72. }
  73. /**
  74. * Will return the closest avd to the projects target
  75. * or undefined if no avds exist.
  76. * Returns a promise.
  77. */
  78. module.exports.best_image = function() {
  79. var project_target = this.get_target().replace('android-', '');
  80. return this.list_images()
  81. .then(function(images) {
  82. var closest = 9999;
  83. var best = images[0];
  84. for (i in images) {
  85. var target = images[i].target;
  86. if(target) {
  87. var num = target.split('(API level ')[1].replace(')', '');
  88. if (num == project_target) {
  89. return images[i];
  90. } else if (project_target - num < closest && project_target > num) {
  91. var closest = project_target - num;
  92. best = images[i];
  93. }
  94. }
  95. }
  96. return best;
  97. });
  98. }
  99. // Returns a promise.
  100. module.exports.list_started = function() {
  101. return exec('adb devices')
  102. .then(function(output) {
  103. var response = output.split('\n');
  104. var started_emulator_list = [];
  105. for (var i = 1; i < response.length; i++) {
  106. if (response[i].match(/device/) && response[i].match(/emulator/)) {
  107. started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
  108. }
  109. }
  110. return started_emulator_list;
  111. });
  112. }
  113. module.exports.get_target = function() {
  114. var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
  115. return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
  116. }
  117. // Returns a promise.
  118. module.exports.list_targets = function() {
  119. return exec('android list targets')
  120. .then(function(output) {
  121. var target_out = output.split('\n');
  122. var targets = [];
  123. for (var i = target_out.length; i >= 0; i--) {
  124. if(target_out[i].match(/id:/)) {
  125. targets.push(targets[i].split(' ')[1]);
  126. }
  127. }
  128. return targets;
  129. });
  130. }
  131. /*
  132. * Starts an emulator with the given ID,
  133. * and returns the started ID of that emulator.
  134. * If no ID is given it will used the first image available,
  135. * if no image is available it will error out (maybe create one?).
  136. *
  137. * Returns a promise.
  138. */
  139. module.exports.start = function(emulator_ID) {
  140. var self = this;
  141. var emulator_id, num_started, started_emulators;
  142. return self.list_started()
  143. .then(function(list) {
  144. started_emulators = list;
  145. num_started = started_emulators.length;
  146. if (typeof emulator_ID === 'undefined') {
  147. return self.list_images()
  148. .then(function(emulator_list) {
  149. if (emulator_list.length > 0) {
  150. return self.best_image()
  151. .then(function(best) {
  152. emulator_ID = best.name;
  153. console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
  154. return emulator_ID;
  155. });
  156. } else {
  157. return Q.reject('ERROR : No emulator images (avds) found, if you would like to create an\n' +
  158. ' avd follow the instructions provided here:\n' +
  159. ' http://developer.android.com/tools/devices/index.html\n' +
  160. ' Or run \'android create avd --name <name> --target <targetID>\'\n' +
  161. ' in on the command line.');
  162. }
  163. });
  164. } else {
  165. return Q(emulator_ID);
  166. }
  167. }).then(function() {
  168. var cmd = 'emulator';
  169. var args = ['-avd', emulator_ID];
  170. var proc = child_process.spawn(cmd, args, { stdio: 'inherit', detached: true });
  171. proc.unref(); // Don't wait for it to finish, since the emulator will probably keep running for a long time.
  172. }).then(function() {
  173. // wait for emulator to start
  174. console.log('Waiting for emulator...');
  175. return self.wait_for_emulator(num_started);
  176. }).then(function(new_started) {
  177. if (new_started.length > 1) {
  178. for (i in new_started) {
  179. if (started_emulators.indexOf(new_started[i]) < 0) {
  180. emulator_id = new_started[i];
  181. }
  182. }
  183. } else {
  184. emulator_id = new_started[0];
  185. }
  186. if (!emulator_id) return Q.reject('ERROR : Failed to start emulator, could not find new emulator');
  187. //wait for emulator to boot up
  188. process.stdout.write('Booting up emulator (this may take a while)...');
  189. return self.wait_for_boot(emulator_id);
  190. }).then(function() {
  191. console.log('BOOT COMPLETE');
  192. //unlock screen
  193. return exec('adb -s ' + emulator_id + ' shell input keyevent 82');
  194. }).then(function() {
  195. //return the new emulator id for the started emulators
  196. return emulator_id;
  197. });
  198. }
  199. /*
  200. * Waits for the new emulator to apear on the started-emulator list.
  201. * Returns a promise with a list of newly started emulators' IDs.
  202. */
  203. module.exports.wait_for_emulator = function(num_running) {
  204. var self = this;
  205. return self.list_started()
  206. .then(function(new_started) {
  207. if (new_started.length > num_running) {
  208. return new_started;
  209. } else {
  210. return Q.delay(1000).then(function() {
  211. return self.wait_for_emulator(num_running);
  212. });
  213. }
  214. });
  215. }
  216. /*
  217. * Waits for the boot animation property of the emulator to switch to 'stopped'
  218. */
  219. module.exports.wait_for_boot = function(emulator_id) {
  220. var self = this;
  221. return exec('adb -s ' + emulator_id + ' shell getprop init.svc.bootanim')
  222. .then(function(output) {
  223. if (output.match(/stopped/)) {
  224. return;
  225. } else {
  226. process.stdout.write('.');
  227. return Q.delay(3000).then(function() {
  228. return self.wait_for_boot(emulator_id);
  229. });
  230. }
  231. });
  232. }
  233. /*
  234. * Create avd
  235. * TODO : Enter the stdin input required to complete the creation of an avd.
  236. * Returns a promise.
  237. */
  238. module.exports.create_image = function(name, target) {
  239. console.log('Creating avd named ' + name);
  240. if (target) {
  241. return exec('android create avd --name ' + name + ' --target ' + target)
  242. .then(null, function(error) {
  243. console.error('ERROR : Failed to create emulator image : ');
  244. console.error(' Do you have the latest android targets including ' + target + '?');
  245. console.error(create.output);
  246. });
  247. } else {
  248. console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
  249. return exec('android create avd --name ' + name + ' --target ' + this.list_targets()[0])
  250. .then(function() {
  251. // TODO: This seems like another error case, even though it always happens.
  252. console.error('ERROR : Unable to create an avd emulator, no targets found.');
  253. console.error('Please insure you have targets available by running the "android" command');
  254. return Q.reject();
  255. }, function(error) {
  256. console.error('ERROR : Failed to create emulator image : ');
  257. console.error(error);
  258. });
  259. }
  260. }
  261. /*
  262. * Installs a previously built application on the emulator and launches it.
  263. * If no target is specified, then it picks one.
  264. * If no started emulators are found, error out.
  265. * Returns a promise.
  266. */
  267. module.exports.install = function(target, buildResults) {
  268. var self = this;
  269. return this.list_started()
  270. .then(function(emulator_list) {
  271. if (emulator_list.length < 1) {
  272. return Q.reject('No started emulators found, please start an emultor before deploying your project.');
  273. }
  274. // default emulator
  275. target = target || emulator_list[0];
  276. if (emulator_list.indexOf(target) < 0) {
  277. return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
  278. }
  279. return build.detectArchitecture(target)
  280. .then(function(arch) {
  281. var apk_path = build.findBestApkForArchitecture(buildResults, arch);
  282. console.log('Installing app on emulator...');
  283. console.log('Using apk: ' + apk_path);
  284. return exec('adb -s ' + target + ' install -r "' + apk_path + '"');
  285. });
  286. }).then(function(output) {
  287. if (output.match(/Failure/)) {
  288. return Q.reject('Failed to install apk to emulator: ' + output);
  289. }
  290. return Q();
  291. }, function(err) {
  292. return Q.reject('Failed to install apk to emulator: ' + err);
  293. }).then(function() {
  294. //unlock screen
  295. return exec('adb -s ' + target + ' shell input keyevent 82');
  296. }).then(function() {
  297. // launch the application
  298. console.log('Launching application...');
  299. var launchName = appinfo.getActivityName();
  300. cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
  301. return exec(cmd);
  302. }).then(function(output) {
  303. console.log('LAUNCH SUCCESS');
  304. }, function(err) {
  305. return Q.reject('Failed to launch app on emulator: ' + err);
  306. });
  307. }