You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2017/05/01 21:17:24 UTC
[42/63] [abbrv] cordova-lib git commit: CB-11242: updated tests and
fixtures
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GradleBuilder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GradleBuilder.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GradleBuilder.js
new file mode 100644
index 0000000..5b5ce13
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GradleBuilder.js
@@ -0,0 +1,279 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var util = require('util');
+var path = require('path');
+var shell = require('shelljs');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var check_reqs = require('../check_reqs');
+
+var GenericBuilder = require('./GenericBuilder');
+
+var MARKER = 'YOUR CHANGES WILL BE ERASED!';
+var SIGNING_PROPERTIES = '-signing.properties';
+var TEMPLATE =
+ '# This file is automatically generated.\n' +
+ '# Do not modify this file -- ' + MARKER + '\n';
+
+function GradleBuilder (projectRoot) {
+ GenericBuilder.call(this, projectRoot);
+
+ this.binDirs = {gradle: this.binDirs.gradle};
+}
+
+util.inherits(GradleBuilder, GenericBuilder);
+
+GradleBuilder.prototype.getArgs = function(cmd, opts) {
+ if (cmd == 'release') {
+ cmd = 'cdvBuildRelease';
+ } else if (cmd == 'debug') {
+ cmd = 'cdvBuildDebug';
+ }
+ var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
+ if (opts.arch) {
+ args.push('-PcdvBuildArch=' + opts.arch);
+ }
+
+ // 10 seconds -> 6 seconds
+ args.push('-Dorg.gradle.daemon=true');
+ // to allow dex in process
+ args.push('-Dorg.gradle.jvmargs=-Xmx2048m');
+ // allow NDK to be used - required by Gradle 1.5 plugin
+ args.push('-Pandroid.useDeprecatedNdk=true');
+ args.push.apply(args, opts.extraArgs);
+ // Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
+ // args.push('-Dorg.gradle.parallel=true');
+ return args;
+};
+
+/*
+ * This returns a promise
+ */
+
+GradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) {
+ var gradlePath = path.join(this.root, 'gradlew');
+ var wrapperGradle = path.join(this.root, 'wrapper.gradle');
+ if(fs.existsSync(gradlePath)) {
+ //Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
+ } else {
+ return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'});
+ }
+};
+
+
+// Makes the project buildable, minus the gradle wrapper.
+GradleBuilder.prototype.prepBuildFiles = function() {
+ // Update the version of build.gradle in each dependent library.
+ var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
+ var propertiesObj = this.readProjectProperties();
+ var subProjects = propertiesObj.libs;
+ var checkAndCopy = function(subProject, root) {
+ var subProjectGradle = path.join(root, subProject, 'build.gradle');
+ // This is the future-proof way of checking if a file exists
+ // This must be synchronous to satisfy a Travis test
+ try {
+ fs.accessSync(subProjectGradle, fs.F_OK);
+ } catch (e) {
+ shell.cp('-f', pluginBuildGradle, subProjectGradle);
+ }
+ };
+ for (var i = 0; i < subProjects.length; ++i) {
+ if (subProjects[i] !== 'CordovaLib') {
+ checkAndCopy(subProjects[i], this.root);
+ }
+ }
+ var name = this.extractRealProjectNameFromManifest();
+ //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
+ var settingsGradlePaths = subProjects.map(function(p){
+ var realDir=p.replace(/[/\\]/g, ':');
+ var libName=realDir.replace(name+'-','');
+ var str='include ":'+libName+'"\n';
+ if(realDir.indexOf(name+'-')!==-1)
+ str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
+ return str;
+ });
+
+ // Write the settings.gradle file.
+ fs.writeFileSync(path.join(this.root, 'settings.gradle'),
+ '// GENERATED FILE - DO NOT EDIT\n' +
+ 'include ":"\n' + settingsGradlePaths.join(''));
+ // Update dependencies within build.gradle.
+ var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
+ var depsList = '';
+ var root = this.root;
+ var insertExclude = function(p) {
+ var gradlePath = path.join(root, p, 'build.gradle');
+ var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
+ if(projectGradleFile.indexOf('CordovaLib') != -1) {
+ depsList += '{\n exclude module:("CordovaLib")\n }\n';
+ }
+ else {
+ depsList +='\n';
+ }
+ };
+ subProjects.forEach(function(p) {
+ console.log('Subproject Path: ' + p);
+ var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
+ depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))';
+ insertExclude(p);
+ depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
+ insertExclude(p);
+ });
+ // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
+ var SYSTEM_LIBRARY_MAPPINGS = [
+ [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
+ [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
+ ];
+ propertiesObj.systemLibs.forEach(function(p) {
+ var mavenRef;
+ // It's already in gradle form if it has two ':'s
+ if (/:.*:/.exec(p)) {
+ mavenRef = p;
+ } else {
+ for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
+ var pair = SYSTEM_LIBRARY_MAPPINGS[i];
+ if (pair[0].exec(p)) {
+ mavenRef = p.replace(pair[0], pair[1]);
+ break;
+ }
+ }
+ if (!mavenRef) {
+ throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
+ }
+ }
+ depsList += ' compile "' + mavenRef + '"\n';
+ });
+ buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
+ var includeList = '';
+ propertiesObj.gradleIncludes.forEach(function(includePath) {
+ includeList += 'apply from: "' + includePath + '"\n';
+ });
+ buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
+ fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
+};
+
+GradleBuilder.prototype.prepEnv = function(opts) {
+ var self = this;
+ return check_reqs.check_gradle()
+ .then(function(gradlePath) {
+ return self.runGradleWrapper(gradlePath);
+ }).then(function() {
+ return self.prepBuildFiles();
+ }).then(function() {
+ // We now copy the gradle out of the framework
+ // This is a dirty patch to get the build working
+ /*
+ var wrapperDir = path.join(self.root, 'CordovaLib');
+ if (process.platform == 'win32') {
+ shell.rm('-f', path.join(self.root, 'gradlew.bat'));
+ shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
+ } else {
+ shell.rm('-f', path.join(self.root, 'gradlew'));
+ shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
+ }
+ shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
+ shell.mkdir('-p', path.join(self.root, 'gradle'));
+ shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
+*/
+ // If the gradle distribution URL is set, make sure it points to version we want.
+ // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
+ // For some reason, using ^ and $ don't work. This does the job, though.
+ var distributionUrlRegex = /distributionUrl.*zip/;
+ /*jshint -W069 */
+ var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip';
+ /*jshint +W069 */
+ var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
+ shell.chmod('u+w', gradleWrapperPropertiesPath);
+ shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
+
+ var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+ var propertiesFilePath = path.join(self.root, propertiesFile);
+ if (opts.packageInfo) {
+ fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+ } else if (isAutoGenerated(propertiesFilePath)) {
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+};
+
+/*
+ * Builds the project with gradle.
+ * Returns a promise.
+ */
+GradleBuilder.prototype.build = function(opts) {
+ var wrapper = path.join(this.root, 'gradlew');
+ var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
+
+ return spawn(wrapper, args, {stdio: 'pipe'})
+ .progress(function (stdio){
+ if (stdio.stderr) {
+ /*
+ * Workaround for the issue with Java printing some unwanted information to
+ * stderr instead of stdout.
+ * This function suppresses 'Picked up _JAVA_OPTIONS' message from being
+ * printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
+ * explanation.
+ */
+ var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
+ if (suppressThisLine) {
+ return;
+ }
+ process.stderr.write(stdio.stderr);
+ } else {
+ process.stdout.write(stdio.stdout);
+ }
+ }).catch(function (error) {
+ if (error.toString().indexOf('failed to find target with hash string') >= 0) {
+ return check_reqs.check_android_target(error).then(function() {
+ // If due to some odd reason - check_android_target succeeds
+ // we should still fail here.
+ return Q.reject(error);
+ });
+ }
+ return Q.reject(error);
+ });
+};
+
+GradleBuilder.prototype.clean = function(opts) {
+ var builder = this;
+ var wrapper = path.join(this.root, 'gradlew');
+ var args = builder.getArgs('clean', opts);
+ return Q().then(function() {
+ return spawn(wrapper, args, {stdio: 'inherit'});
+ })
+ .then(function () {
+ shell.rm('-rf', path.join(builder.root, 'out'));
+
+ ['debug', 'release'].forEach(function(config) {
+ var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
+ if(isAutoGenerated(propertiesFilePath)){
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+ });
+};
+
+module.exports = GradleBuilder;
+
+function isAutoGenerated(file) {
+ return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/builders.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/builders.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/builders.js
new file mode 100644
index 0000000..4921c49
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/builders.js
@@ -0,0 +1,47 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var CordovaError = require('cordova-common').CordovaError;
+
+var knownBuilders = {
+ ant: 'AntBuilder',
+ gradle: 'GradleBuilder',
+ none: 'GenericBuilder'
+};
+
+/**
+ * Helper method that instantiates and returns a builder for specified build
+ * type.
+ *
+ * @param {String} builderType Builder name to construct and return. Must
+ * be one of 'ant', 'gradle' or 'none'
+ *
+ * @return {Builder} A builder instance for specified build type.
+ */
+module.exports.getBuilder = function (builderType, projectRoot) {
+ if (!knownBuilders[builderType])
+ throw new CordovaError('Builder ' + builderType + ' is not supported.');
+
+ try {
+ var Builder = require('./' + knownBuilders[builderType]);
+ return new Builder(projectRoot);
+ } catch (err) {
+ throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/check_reqs.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/check_reqs.js
new file mode 100644
index 0000000..1fd397a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/check_reqs.js
@@ -0,0 +1,432 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+/* jshint sub:true */
+
+var shelljs = require('shelljs'),
+ child_process = require('child_process'),
+ Q = require('q'),
+ path = require('path'),
+ fs = require('fs'),
+ os = require('os'),
+ REPO_ROOT = path.join(__dirname, '..', '..', '..', '..'),
+ PROJECT_ROOT = path.join(__dirname, '..', '..');
+var CordovaError = require('cordova-common').CordovaError;
+var superspawn = require('cordova-common').superspawn;
+var android_sdk = require('./android_sdk');
+
+function forgivingWhichSync(cmd) {
+ try {
+ return fs.realpathSync(shelljs.which(cmd));
+ } catch (e) {
+ return '';
+ }
+}
+
+function tryCommand(cmd, errMsg, catchStderr) {
+ var d = Q.defer();
+ child_process.exec(cmd, function(err, stdout, stderr) {
+ if (err) d.reject(new CordovaError(errMsg));
+ // Sometimes it is necessary to return an stderr instead of stdout in case of success, since
+ // some commands prints theirs output to stderr instead of stdout. 'javac' is the example
+ else d.resolve((catchStderr ? stderr : stdout).trim());
+ });
+ return d.promise;
+}
+
+module.exports.isWindows = function() {
+ return (os.platform() == 'win32');
+};
+
+module.exports.isDarwin = function() {
+ return (os.platform() == 'darwin');
+};
+
+// Get valid target from framework/project.properties if run from this repo
+// Otherwise get target from project.properties file within a generated cordova-android project
+module.exports.get_target = function() {
+ function extractFromFile(filePath) {
+ var target = shelljs.grep(/\btarget=/, filePath);
+ if (!target) {
+ throw new Error('Could not find android target within: ' + filePath);
+ }
+ return target.split('=')[1].trim();
+ }
+ var repo_file = path.join(REPO_ROOT, 'framework', 'project.properties');
+ if (fs.existsSync(repo_file)) {
+ return extractFromFile(repo_file);
+ }
+ var project_file = path.join(PROJECT_ROOT, 'project.properties');
+ if (fs.existsSync(project_file)) {
+ // if no target found, we're probably in a project and project.properties is in PROJECT_ROOT.
+ return extractFromFile(project_file);
+ }
+ throw new Error('Could not find android target in either ' + repo_file + ' nor ' + project_file);
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_ant = function() {
+ return superspawn.spawn('ant', ['-version'])
+ .then(function(output) {
+ // Parse Ant version from command output
+ return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
+ }).catch(function(err) {
+ throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
+ });
+};
+
+module.exports.get_gradle_wrapper = function() {
+ var androidStudioPath;
+ var i = 0;
+ var foundStudio = false;
+ var program_dir;
+ if (module.exports.isDarwin()) {
+ program_dir = fs.readdirSync('/Applications');
+ while (i < program_dir.length && !foundStudio) {
+ if (program_dir[i].startsWith('Android Studio')) {
+ //TODO: Check for a specific Android Studio version, make sure it's not Canary
+ androidStudioPath = path.join('/Applications', program_dir[i], 'Contents', 'gradle');
+ foundStudio = true;
+ } else { ++i; }
+ }
+ } else if (module.exports.isWindows()) {
+ var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
+ if (fs.existsSync(androidPath)) {
+ program_dir = fs.readdirSync(androidPath);
+ while (i < program_dir.length && !foundStudio) {
+ if (program_dir[i].startsWith('Android Studio')) {
+ foundStudio = true;
+ androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
+ } else { ++i; }
+ }
+ }
+ }
+
+ if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
+ var dirs = fs.readdirSync(androidStudioPath);
+ if(dirs[0].split('-')[0] == 'gradle') {
+ return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');
+ }
+ } else {
+ //OK, let's try to check for Gradle!
+ return forgivingWhichSync('gradle');
+ }
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_gradle = function() {
+ var sdkDir = process.env['ANDROID_HOME'];
+ var d = Q.defer();
+ if (!sdkDir)
+ return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
+ 'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
+
+ var gradlePath = module.exports.get_gradle_wrapper();
+ if (gradlePath.length !== 0)
+ d.resolve(gradlePath);
+ else
+ d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' +
+ 'or on your system to install the gradle wrapper. Please include gradle \n' +
+ 'in your path, or install Android Studio'));
+ return d.promise;
+};
+
+// Returns a promise.
+module.exports.check_java = function() {
+ var javacPath = forgivingWhichSync('javac');
+ var hasJavaHome = !!process.env['JAVA_HOME'];
+ return Q().then(function() {
+ if (hasJavaHome) {
+ // Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
+ if (!javacPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
+ }
+ } else {
+ if (javacPath) {
+ // OS X has a command for finding JAVA_HOME.
+ var find_java = '/usr/libexec/java_home';
+ var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
+ if (fs.existsSync(find_java)) {
+ return superspawn.spawn(find_java)
+ .then(function(stdout) {
+ process.env['JAVA_HOME'] = stdout.trim();
+ }).catch(function(err) {
+ throw new CordovaError(default_java_error_msg);
+ });
+ } else {
+ // See if we can derive it from javac's location.
+ // fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
+ var maybeJavaHome = path.dirname(path.dirname(javacPath));
+ if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
+ process.env['JAVA_HOME'] = maybeJavaHome;
+ } else {
+ throw new CordovaError(default_java_error_msg);
+ }
+ }
+ } else if (module.exports.isWindows()) {
+ // Try to auto-detect java in the default install paths.
+ var oldSilent = shelljs.config.silent;
+ shelljs.config.silent = true;
+ var firstJdkDir =
+ shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
+ shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
+ shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
+ shelljs.config.silent = oldSilent;
+ if (firstJdkDir) {
+ // shelljs always uses / in paths.
+ firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
+ if (!javacPath) {
+ process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
+ }
+ process.env['JAVA_HOME'] = firstJdkDir;
+ }
+ }
+ }
+ }).then(function() {
+ var msg =
+ 'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
+ 'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
+ if (process.env['JAVA_HOME']) {
+ msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
+ }
+ // We use tryCommand with catchStderr = true, because
+ // javac writes version info to stderr instead of stdout
+ return tryCommand('javac -version', msg, true)
+ .then(function (output) {
+ //Let's check for at least Java 8, and keep it future proof so we can support Java 10
+ var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
+ return match && match[1];
+ });
+ });
+};
+
+// Returns a promise.
+module.exports.check_android = function() {
+ return Q().then(function() {
+ var androidCmdPath = forgivingWhichSync('android');
+ var adbInPath = forgivingWhichSync('adb');
+ var avdmanagerInPath = forgivingWhichSync('avdmanager');
+ var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
+ function maybeSetAndroidHome(value) {
+ if (!hasAndroidHome && fs.existsSync(value)) {
+ hasAndroidHome = true;
+ process.env['ANDROID_HOME'] = value;
+ }
+ }
+ // First ensure ANDROID_HOME is set
+ // If we have no hints (nothing in PATH), try a few default locations
+ if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {
+ if (module.exports.isWindows()) {
+ // Android Studio 1.0 installer
+ maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
+ maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
+ // Android Studio pre-1.0 installer
+ maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));
+ maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));
+ // Stand-alone installer
+ maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
+ maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
+ } else if (module.exports.isDarwin()) {
+ // Android Studio 1.0 installer
+ maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
+ // Android Studio pre-1.0 installer
+ maybeSetAndroidHome('/Applications/Android Studio.app/sdk');
+ // Stand-alone zip file that user might think to put under /Applications
+ maybeSetAndroidHome('/Applications/android-sdk-macosx');
+ maybeSetAndroidHome('/Applications/android-sdk');
+ }
+ if (process.env['HOME']) {
+ // Stand-alone zip file that user might think to put under their home directory
+ maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));
+ maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
+ }
+ }
+ if (!hasAndroidHome) {
+ // If we dont have ANDROID_HOME, but we do have some tools on the PATH, try to infer from the tooling PATH.
+ var parentDir, grandParentDir;
+ if (androidCmdPath) {
+ parentDir = path.dirname(androidCmdPath);
+ grandParentDir = path.dirname(parentDir);
+ if (path.basename(parentDir) == 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
+ maybeSetAndroidHome(grandParentDir);
+ } else {
+ throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+ 'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
+ 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');
+ }
+ }
+ if (adbInPath) {
+ parentDir = path.dirname(adbInPath);
+ grandParentDir = path.dirname(parentDir);
+ if (path.basename(parentDir) == 'platform-tools') {
+ maybeSetAndroidHome(grandParentDir);
+ } else {
+ throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+ 'Detected \'adb\' command at ' + parentDir + ' but no \'platform-tools\' directory found near.\n' +
+ 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');
+ }
+ }
+ if (avdmanagerInPath) {
+ parentDir = path.dirname(avdmanagerInPath);
+ grandParentDir = path.dirname(parentDir);
+ if (path.basename(parentDir) == 'bin' && path.basename(grandParentDir) == 'tools') {
+ maybeSetAndroidHome(path.dirname(grandParentDir));
+ } else {
+ throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+ 'Detected \'avdmanager\' command at ' + parentDir + ' but no \'tools' + path.sep + 'bin\' directory found near.\n' +
+ 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');
+ }
+ }
+ }
+ if (!process.env['ANDROID_HOME']) {
+ throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+ 'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
+ }
+ if (!fs.existsSync(process.env['ANDROID_HOME'])) {
+ throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
+ '\nTry update it manually to point to valid SDK directory.');
+ }
+ // Next let's make sure relevant parts of the SDK tooling is in our PATH
+ if (hasAndroidHome && !androidCmdPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
+ }
+ if (hasAndroidHome && !adbInPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
+ }
+ if (hasAndroidHome && !avdmanagerInPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools', 'bin');
+ }
+ return hasAndroidHome;
+ });
+};
+
+// TODO: is this actually needed?
+module.exports.getAbsoluteAndroidCmd = function () {
+ var cmd = forgivingWhichSync('android');
+ if (cmd.length === 0) {
+ cmd = forgivingWhichSync('sdkmanager');
+ }
+ if (module.exports.isWindows()) {
+ return '"' + cmd + '"';
+ }
+ return cmd.replace(/(\s)/g, '\\$1');
+};
+
+module.exports.check_android_target = function(originalError) {
+ // valid_target can look like:
+ // android-19
+ // android-L
+ // Google Inc.:Google APIs:20
+ // Google Inc.:Glass Development Kit Preview:20
+ var desired_api_level = module.exports.get_target();
+ return android_sdk.list_targets()
+ .then(function(targets) {
+ if (targets.indexOf(desired_api_level) >= 0) {
+ return targets;
+ }
+ var androidCmd = module.exports.getAbsoluteAndroidCmd();
+ var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' +
+ 'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
+ 'You will require:\n' +
+ '1. "SDK Platform" for API level ' + desired_api_level + '\n' +
+ '2. "Android SDK Platform-tools (latest)\n' +
+ '3. "Android SDK Build-tools" (latest)';
+ if (originalError) {
+ msg = originalError + '\n' + msg;
+ }
+ throw new CordovaError(msg);
+ });
+};
+
+// Returns a promise.
+module.exports.run = function() {
+ return Q.all([this.check_java(), this.check_android()])
+ .then(function(values) {
+ console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
+ console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
+
+ if (!values[0]) {
+ throw new CordovaError('Requirements check failed for JDK 1.8 or greater');
+ }
+
+ if (!values[1]) {
+ throw new CordovaError('Requirements check failed for Android SDK');
+ }
+ });
+};
+
+
+/**
+ * Object thar represents one of requirements for current platform.
+ * @param {String} id The unique identifier for this requirements.
+ * @param {String} name The name of requirements. Human-readable field.
+ * @param {String} version The version of requirement installed. In some cases could be an array of strings
+ * (for example, check_android_target returns an array of android targets installed)
+ * @param {Boolean} installed Indicates whether the requirement is installed or not
+ */
+var Requirement = function (id, name, version, installed) {
+ this.id = id;
+ this.name = name;
+ this.installed = installed || false;
+ this.metadata = {
+ version: version,
+ };
+};
+
+/**
+ * Methods that runs all checks one by one and returns a result of checks
+ * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
+ *
+ * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
+ */
+module.exports.check_all = function() {
+
+ var requirements = [
+ new Requirement('java', 'Java JDK'),
+ new Requirement('androidSdk', 'Android SDK'),
+ new Requirement('androidTarget', 'Android target'),
+ new Requirement('gradle', 'Gradle')
+ ];
+
+ var checkFns = [
+ this.check_java,
+ this.check_android,
+ this.check_android_target,
+ this.check_gradle
+ ];
+
+ // Then execute requirement checks one-by-one
+ return checkFns.reduce(function (promise, checkFn, idx) {
+ // Update each requirement with results
+ var requirement = requirements[idx];
+ return promise.then(checkFn)
+ .then(function (version) {
+ requirement.installed = true;
+ requirement.metadata.version = version;
+ }, function (err) {
+ requirement.metadata.reason = err instanceof Error ? err.message : err;
+ });
+ }, Q())
+ .then(function () {
+ // When chain is completed, return requirements array to upstream API
+ return requirements;
+ });
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/device.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/device.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/device.js
new file mode 100644
index 0000000..4b171db
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/device.js
@@ -0,0 +1,120 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var Q = require('q'),
+ build = require('./build');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var events = require('cordova-common').events;
+
+/**
+ * Returns a promise for the list of the device ID's found
+ * @param lookHarder When true, try restarting adb if no devices are found.
+ */
+module.exports.list = function(lookHarder) {
+ return Adb.devices()
+ .then(function(list) {
+ if (list.length === 0 && lookHarder) {
+ // adb kill-server doesn't seem to do the trick.
+ // Could probably find a x-platform version of killall, but I'm not actually
+ // sure that this scenario even happens on non-OSX machines.
+ return spawn('killall', ['adb'])
+ .then(function() {
+ events.emit('verbose', 'Restarting adb to see if more devices are detected.');
+ return Adb.devices();
+ }, function() {
+ // For non-killall OS's.
+ return list;
+ });
+ }
+ return list;
+ });
+};
+
+module.exports.resolveTarget = function(target) {
+ return this.list(true)
+ .then(function(device_list) {
+ if (!device_list || !device_list.length) {
+ return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
+ }
+ // default device
+ target = target || device_list[0];
+
+ if (device_list.indexOf(target) < 0) {
+ return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
+ }
+
+ return build.detectArchitecture(target)
+ .then(function(arch) {
+ return { target: target, arch: arch, isEmulator: false };
+ });
+ });
+};
+
+/*
+ * Installs a previously built application on the device
+ * and launches it.
+ * Returns a promise.
+ */
+module.exports.install = function(target, buildResults) {
+ return Q().then(function() {
+ if (target && typeof target == 'object') {
+ return target;
+ }
+ return module.exports.resolveTarget(target);
+ }).then(function(resolvedTarget) {
+ var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
+ var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
+ var pkgName = manifest.getPackageId();
+ var launchName = pkgName + '/.' + manifest.getActivity().getName();
+ events.emit('log', 'Using apk: ' + apk_path);
+ events.emit('log', 'Package name: ' + pkgName);
+
+ return Adb.install(resolvedTarget.target, apk_path, {replace: true})
+ .catch(function (error) {
+ // CB-9557 CB-10157 only uninstall and reinstall app if the one that
+ // is already installed on device was signed w/different certificate
+ if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
+ throw error;
+
+ events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
+ 'installed app already signed with different key');
+
+ // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+ // or the app doesn't installed at all, so no error catching needed.
+ return Adb.uninstall(resolvedTarget.target, pkgName)
+ .then(function() {
+ return Adb.install(resolvedTarget.target, apk_path, {replace: true});
+ });
+ })
+ .then(function() {
+ //unlock screen
+ return Adb.shell(resolvedTarget.target, 'input keyevent 82');
+ }).then(function() {
+ return Adb.start(resolvedTarget.target, launchName);
+ }).then(function() {
+ events.emit('log', 'LAUNCH SUCCESS');
+ });
+ });
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/emulator.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/emulator.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/emulator.js
new file mode 100644
index 0000000..2f36b9a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/emulator.js
@@ -0,0 +1,540 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+/* jshint sub:true */
+
+var retry = require('./retry');
+var build = require('./build');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var events = require('cordova-common').events;
+var superspawn = require('cordova-common').superspawn;
+var CordovaError = require('cordova-common').CordovaError;
+var shelljs = require('shelljs');
+var android_sdk = require('./android_sdk');
+var check_reqs = require('./check_reqs');
+
+var Q = require('q');
+var os = require('os');
+var fs = require('fs');
+var child_process = require('child_process');
+
+// constants
+var ONE_SECOND = 1000; // in milliseconds
+var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
+var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
+var NUM_INSTALL_RETRIES = 3;
+var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
+var EXEC_KILL_SIGNAL = 'SIGKILL';
+
+function forgivingWhichSync(cmd) {
+ try {
+ return fs.realpathSync(shelljs.which(cmd));
+ } catch (e) {
+ return '';
+ }
+}
+
+module.exports.list_images_using_avdmanager = function () {
+ return superspawn.spawn('avdmanager', ['list', 'avd'])
+ .then(function(output) {
+ var response = output.split('\n');
+ var emulator_list = [];
+ for (var i = 1; i < response.length; i++) {
+ // To return more detailed information use img_obj
+ var img_obj = {};
+ if (response[i].match(/Name:\s/)) {
+ img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+ if (response[i + 1].match(/Device:\s/)) {
+ i++;
+ img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/Path:\s/)) {
+ i++;
+ img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/Target:\s/)) {
+ i++;
+ if (response[i + 1].match(/ABI:\s/)) {
+ img_obj['abi'] = response[i + 1].split('ABI: ')[1].replace('\r', '');
+ }
+ // This next conditional just aims to match the old output of `android list avd`
+ // We do so so that we don't have to change the logic when parsing for the
+ // best emulator target to spawn (see below in `best_image`)
+ // This allows us to transitionally support both `android` and `avdmanager` binaries,
+ // depending on what SDK version the user has
+ if (response[i + 1].match(/Based\son:\s/)) {
+ img_obj['target'] = response[i + 1].split('Based on:')[1];
+ if (img_obj['target'].match(/Tag\/ABI:\s/)) {
+ img_obj['target'] = img_obj['target'].split('Tag/ABI:')[0].replace('\r', '').trim();
+ if (img_obj['target'].indexOf('(') > -1) {
+ img_obj['target'] = img_obj['target'].substr(0, img_obj['target'].indexOf('(') - 1).trim();
+ }
+ }
+ var version_string = img_obj['target'].replace(/Android\s+/, '');
+
+ var api_level = android_sdk.version_string_to_api_level[version_string];
+ if (api_level) {
+ img_obj['target'] += ' (API level ' + api_level + ')';
+ }
+ }
+ }
+ if (response[i + 1].match(/Skin:\s/)) {
+ i++;
+ img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
+ }
+
+ emulator_list.push(img_obj);
+ }
+ /* To just return a list of names use this
+ if (response[i].match(/Name:\s/)) {
+ emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
+ }*/
+
+ }
+ return emulator_list;
+ });
+};
+
+module.exports.list_images_using_android = function() {
+ return superspawn.spawn('android', ['list', 'avds'])
+ .then(function(output) {
+ var response = output.split('\n');
+ var emulator_list = [];
+ for (var i = 1; i < response.length; i++) {
+ // To return more detailed information use img_obj
+ var img_obj = {};
+ if (response[i].match(/Name:\s/)) {
+ img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+ if (response[i + 1].match(/Device:\s/)) {
+ i++;
+ img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/Path:\s/)) {
+ i++;
+ img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/\(API\slevel\s/) || (response[i + 2] && response[i + 2].match(/\(API\slevel\s/))) {
+ i++;
+ var secondLine = response[i + 1].match(/\(API\slevel\s/) ? response[i + 1] : '';
+ img_obj['target'] = (response[i] + secondLine).split('Target: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/ABI:\s/)) {
+ i++;
+ img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/Skin:\s/)) {
+ i++;
+ img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
+ }
+
+ emulator_list.push(img_obj);
+ }
+ /* To just return a list of names use this
+ if (response[i].match(/Name:\s/)) {
+ emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
+ }*/
+
+ }
+ return emulator_list;
+ });
+};
+
+/**
+ * Returns a Promise for a list of emulator images in the form of objects
+ * {
+ name : <emulator_name>,
+ device : <device>,
+ path : <path_to_emulator_image>,
+ target : <api_target>,
+ abi : <cpu>,
+ skin : <skin>
+ }
+ */
+module.exports.list_images = function() {
+ if (forgivingWhichSync('android')) {
+ return module.exports.list_images_using_android()
+ .catch(function(err) {
+ // try to use `avdmanager` in case `android` reports it is no longer available.
+ // this likely means the target machine is using a newer version of
+ // the android sdk, and possibly `avdmanager` is available.
+ if (err.code == 1 && err.stdout.indexOf('android command is no longer available')) {
+ return module.exports.list_images_using_avdmanager();
+ } else {
+ throw err;
+ }
+ });
+ } else if (forgivingWhichSync('avdmanager')) {
+ return module.exports.list_images_using_avdmanager();
+ } else {
+ return Q().then(function() {
+ throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?');
+ });
+ }
+};
+
+/**
+ * Will return the closest avd to the projects target
+ * or undefined if no avds exist.
+ * Returns a promise.
+ */
+module.exports.best_image = function() {
+ return this.list_images()
+ .then(function(images) {
+ // Just return undefined if there is no images
+ if (images.length === 0) return;
+
+ var closest = 9999;
+ var best = images[0];
+ var project_target = check_reqs.get_target().replace('android-', '');
+ for (var i in images) {
+ var target = images[i].target;
+ if(target) {
+ var num = target.split('(API level ')[1].replace(')', '');
+ if (num == project_target) {
+ return images[i];
+ } else if (project_target - num < closest && project_target > num) {
+ closest = project_target - num;
+ best = images[i];
+ }
+ }
+ }
+ return best;
+ });
+};
+
+// Returns a promise.
+module.exports.list_started = function() {
+ return Adb.devices({emulators: true});
+};
+
+// Returns a promise.
+module.exports.list_targets = function() {
+ return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
+ .then(function(output) {
+ var target_out = output.split('\n');
+ var targets = [];
+ for (var i = target_out.length; i >= 0; i--) {
+ if(target_out[i].match(/id:/)) {
+ targets.push(targets[i].split(' ')[1]);
+ }
+ }
+ return targets;
+ });
+};
+
+/*
+ * Gets unused port for android emulator, between 5554 and 5584
+ * Returns a promise.
+ */
+module.exports.get_available_port = function () {
+ var self = this;
+
+ return self.list_started()
+ .then(function (emulators) {
+ for (var p = 5584; p >= 5554; p-=2) {
+ if (emulators.indexOf('emulator-' + p) === -1) {
+ events.emit('verbose', 'Found available port: ' + p);
+ return p;
+ }
+ }
+ throw new CordovaError('Could not find an available avd port');
+ });
+};
+
+/*
+ * Starts an emulator with the given ID,
+ * and returns the started ID of that emulator.
+ * If no ID is given it will use the first image available,
+ * if no image is available it will error out (maybe create one?).
+ * If no boot timeout is given or the value is negative it will wait forever for
+ * the emulator to boot
+ *
+ * Returns a promise.
+ */
+module.exports.start = function(emulator_ID, boot_timeout) {
+ var self = this;
+
+ return Q().then(function() {
+ if (emulator_ID) return Q(emulator_ID);
+
+ return self.best_image()
+ .then(function(best) {
+ if (best && best.name) {
+ events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
+ return best.name;
+ }
+
+ var androidCmd = check_reqs.getAbsoluteAndroidCmd();
+ return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
+ '1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
+ '2. Create an AVD by running: ' + androidCmd + ' avd\n' +
+ 'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
+ });
+ }).then(function(emulatorId) {
+ return self.get_available_port()
+ .then(function (port) {
+ // Figure out the directory the emulator binary runs in, and set the cwd to that directory.
+ // Workaround for https://code.google.com/p/android/issues/detail?id=235461
+ var emulator_dir = path.dirname(shelljs.which('emulator'));
+ var args = ['-avd', emulatorId, '-port', port];
+ // Don't wait for it to finish, since the emulator will probably keep running for a long time.
+ child_process
+ .spawn('emulator', args, { stdio: 'inherit', detached: true, cwd: emulator_dir })
+ .unref();
+
+ // wait for emulator to start
+ events.emit('log', 'Waiting for emulator to start...');
+ return self.wait_for_emulator(port);
+ });
+ }).then(function(emulatorId) {
+ if (!emulatorId)
+ return Q.reject(new CordovaError('Failed to start emulator'));
+
+ //wait for emulator to boot up
+ process.stdout.write('Waiting for emulator to boot (this may take a while)...');
+ return self.wait_for_boot(emulatorId, boot_timeout)
+ .then(function(success) {
+ if (success) {
+ events.emit('log','BOOT COMPLETE');
+ //unlock screen
+ return Adb.shell(emulatorId, 'input keyevent 82')
+ .then(function() {
+ //return the new emulator id for the started emulators
+ return emulatorId;
+ });
+ } else {
+ // We timed out waiting for the boot to happen
+ return null;
+ }
+ });
+ });
+};
+
+/*
+ * Waits for an emulator to boot on a given port.
+ * Returns this emulator's ID in a promise.
+ */
+module.exports.wait_for_emulator = function(port) {
+ var self = this;
+ return Q().then(function() {
+ var emulator_id = 'emulator-' + port;
+ return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
+ .then(function (output) {
+ if (output.indexOf('1') >= 0) {
+ return emulator_id;
+ }
+ return self.wait_for_emulator(port);
+ }, function (error) {
+ if (error && error.message &&
+ (error.message.indexOf('not found') > -1) ||
+ error.message.indexOf('device offline') > -1) {
+ // emulator not yet started, continue waiting
+ return self.wait_for_emulator(port);
+ } else {
+ // something unexpected has happened
+ throw error;
+ }
+ });
+ });
+};
+
+/*
+ * Waits for the core android process of the emulator to start. Returns a
+ * promise that resolves to a boolean indicating success. Not specifying a
+ * time_remaining or passing a negative value will cause it to wait forever
+ */
+module.exports.wait_for_boot = function(emulator_id, time_remaining) {
+ var self = this;
+ return Adb.shell(emulator_id, 'ps')
+ .then(function(output) {
+ if (output.match(/android\.process\.acore/)) {
+ return true;
+ } else if (time_remaining === 0) {
+ return false;
+ } else {
+ process.stdout.write('.');
+
+ // Check at regular intervals
+ return Q.delay(time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL).then(function() {
+ var updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;
+ return self.wait_for_boot(emulator_id, updated_time);
+ });
+ }
+ });
+};
+
+/*
+ * Create avd
+ * TODO : Enter the stdin input required to complete the creation of an avd.
+ * Returns a promise.
+ */
+module.exports.create_image = function(name, target) {
+ console.log('Creating new avd named ' + name);
+ if (target) {
+ return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target])
+ .then(null, function(error) {
+ console.error('ERROR : Failed to create emulator image : ');
+ console.error(' Do you have the latest android targets including ' + target + '?');
+ console.error(error);
+ });
+ } else {
+ console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
+ return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
+ .then(function() {
+ // TODO: This seems like another error case, even though it always happens.
+ console.error('ERROR : Unable to create an avd emulator, no targets found.');
+ console.error('Ensure you have targets available by running the "android" command');
+ return Q.reject();
+ }, function(error) {
+ console.error('ERROR : Failed to create emulator image : ');
+ console.error(error);
+ });
+ }
+};
+
+module.exports.resolveTarget = function(target) {
+ return this.list_started()
+ .then(function(emulator_list) {
+ if (emulator_list.length < 1) {
+ return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
+ }
+
+ // default emulator
+ target = target || emulator_list[0];
+ if (emulator_list.indexOf(target) < 0) {
+ return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
+ }
+
+ return build.detectArchitecture(target)
+ .then(function(arch) {
+ return {target:target, arch:arch, isEmulator:true};
+ });
+ });
+};
+
+/*
+ * Installs a previously built application on the emulator and launches it.
+ * If no target is specified, then it picks one.
+ * If no started emulators are found, error out.
+ * Returns a promise.
+ */
+module.exports.install = function(givenTarget, buildResults) {
+
+ var target;
+ var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
+ var pkgName = manifest.getPackageId();
+
+ // resolve the target emulator
+ return Q().then(function () {
+ if (givenTarget && typeof givenTarget == 'object') {
+ return givenTarget;
+ } else {
+ return module.exports.resolveTarget(givenTarget);
+ }
+
+ // set the resolved target
+ }).then(function (resolvedTarget) {
+ target = resolvedTarget;
+
+ // install the app
+ }).then(function () {
+ // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+ // or the app doesn't installed at all, so no error catching needed.
+ return Q.when()
+ .then(function() {
+
+ var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
+ var execOptions = {
+ cwd: os.tmpdir(),
+ timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
+ killSignal: EXEC_KILL_SIGNAL
+ };
+
+ events.emit('log', 'Using apk: ' + apk_path);
+ events.emit('log', 'Package name: ' + pkgName);
+ events.emit('verbose', 'Installing app on emulator...');
+
+ // A special function to call adb install in specific environment w/ specific options.
+ // Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
+ // to workaround sporadic emulator hangs
+ function adbInstallWithOptions(target, apk, opts) {
+ events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');
+
+ var command = 'adb -s ' + target + ' install -r "' + apk + '"';
+ return Q.promise(function (resolve, reject) {
+ child_process.exec(command, opts, function(err, stdout, stderr) {
+ if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
+ // adb does not return an error code even if installation fails. Instead it puts a specific
+ // message to stdout, so we have to use RegExp matching to detect installation failure.
+ else if (/Failure/.test(stdout)) {
+ if (stdout.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
+ stdout += 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
+ ' or sign and deploy the unsigned apk manually using Android tools.';
+ } else if (stdout.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
+ stdout += 'You\'re trying to install apk with a lower versionCode that is already installed.' +
+ '\nEither uninstall an app or increment the versionCode.';
+ }
+
+ reject(new CordovaError('Failed to install apk to emulator: ' + stdout));
+ } else resolve(stdout);
+ });
+ });
+ }
+
+ function installPromise () {
+ return adbInstallWithOptions(target.target, apk_path, execOptions)
+ .catch(function (error) {
+ // CB-9557 CB-10157 only uninstall and reinstall app if the one that
+ // is already installed on device was signed w/different certificate
+ if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
+ throw error;
+
+ events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
+ 'currently installed app was signed with different key');
+
+ // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+ // or the app doesn't installed at all, so no error catching needed.
+ return Adb.uninstall(target.target, pkgName)
+ .then(function() {
+ return adbInstallWithOptions(target.target, apk_path, execOptions);
+ });
+ });
+ }
+
+ return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)
+ .then(function (output) {
+ events.emit('log', 'INSTALL SUCCESS');
+ });
+ });
+ // unlock screen
+ }).then(function () {
+
+ events.emit('verbose', 'Unlocking screen...');
+ return Adb.shell(target.target, 'input keyevent 82');
+ }).then(function () {
+ Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
+ // report success or failure
+ }).then(function (output) {
+ events.emit('log', 'LAUNCH SUCCESS');
+ });
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device
new file mode 100755
index 0000000..fc4b784
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device
@@ -0,0 +1,42 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var device = require('./device'),
+ args = process.argv;
+
+if(args.length > 2) {
+ var install_target;
+ if (args[2].substring(0, 9) == '--target=') {
+ install_target = args[2].substring(9, args[2].length);
+ device.install(install_target).done(null, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+ });
+ } else {
+ console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+ process.exit(2);
+ }
+} else {
+ device.install().done(null, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+ });
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device.bat
new file mode 100644
index 0000000..ac7214a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-device.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0install-device"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator
new file mode 100755
index 0000000..aa2a34f
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var emulator = require('./emulator'),
+ args = process.argv;
+
+var install_target;
+if(args.length > 2) {
+ if (args[2].substring(0, 9) == '--target=') {
+ install_target = args[2].substring(9, args[2].length);
+ } else {
+ console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+ process.exit(2);
+ }
+}
+
+emulator.install(install_target).done(null, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..1ec6779
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/install-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0install-emulator"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices
new file mode 100755
index 0000000..8e22c7f
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var devices = require('./device');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function() {
+ devices.list().done(function(device_list) {
+ device_list && device_list.forEach(function(dev) {
+ console.log(dev);
+ });
+ }, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..c0bcdd9
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-devices.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-devices"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images
new file mode 100755
index 0000000..25e5c81
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var emulators = require('./emulator');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function() {
+ emulators.list_images().done(function(emulator_list) {
+ emulator_list && emulator_list.forEach(function(emu) {
+ console.log(emu.name);
+ });
+ }, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..661cbf9
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-emulator-images"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+)
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators
new file mode 100755
index 0000000..43ebda2
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var emulators = require('./emulator');
+
+// Usage support for when args are given
+require('./check_reqs').check_android().then(function() {
+ emulators.list_started().done(function(emulator_list) {
+ emulator_list && emulator_list.forEach(function(emu) {
+ console.log(emu);
+ });
+ }, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..a4e88f7
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0list-started-emulators"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/log.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/log.js
new file mode 100644
index 0000000..ebf836d
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/log.js
@@ -0,0 +1,56 @@
+#!/usr/bin/env node
+
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var path = require('path'),
+ os = require('os'),
+ Q = require('q'),
+ child_process = require('child_process'),
+ ROOT = path.join(__dirname, '..', '..');
+
+/*
+ * Starts running logcat in the shell.
+ * Returns a promise.
+ */
+module.exports.run = function() {
+ var d = Q.defer();
+ var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()});
+
+ adb.stdout.on('data', function(data) {
+ var lines = data ? data.toString().split('\n') : [];
+ var out = lines.filter(function(x) { return x.indexOf('nativeGetEnabledTags') < 0; });
+ console.log(out.join('\n'));
+ });
+
+ adb.stderr.on('data', console.error);
+ adb.on('close', function(code) {
+ if (code > 0) {
+ d.reject('Failed to run logcat command.');
+ } else d.resolve();
+ });
+
+ return d.promise;
+};
+
+module.exports.help = function() {
+ console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
+ console.log('Gives the logcat output on the command line.');
+ process.exit(0);
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07bed560/cordova-lib/spec-plugman/projects/android/cordova/lib/plugin-build.gradle
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/plugin-build.gradle b/cordova-lib/spec-plugman/projects/android/cordova/lib/plugin-build.gradle
new file mode 100644
index 0000000..d1c6336
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/plugin-build.gradle
@@ -0,0 +1,70 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+// GENERATED FILE! DO NOT EDIT!
+
+buildscript {
+ repositories {
+ mavenCentral()
+ jcenter()
+ }
+
+ // Switch the Android Gradle plugin version requirement depending on the
+ // installed version of Gradle. This dependency is documented at
+ // http://tools.android.com/tech-docs/new-build-system/version-compatibility
+ // and https://issues.apache.org/jira/browse/CB-8143
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.0.0+'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+ compile fileTree(dir: 'libs', include: '*.jar')
+ debugCompile project(path: ":CordovaLib", configuration: "debug")
+ releaseCompile project(path: ":CordovaLib", configuration: "release")
+}
+
+android {
+ compileSdkVersion cdvCompileSdkVersion
+ buildToolsVersion cdvBuildToolsVersion
+ publishNonDefault true
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_6
+ targetCompatibility JavaVersion.VERSION_1_6
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['assets']
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+}
+
+if (file('build-extras.gradle').exists()) {
+ apply from: 'build-extras.gradle'
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org