summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/android/cordova/lib
diff options
context:
space:
mode:
authorRene Ae <aehtyb@gmail.com>2015-12-04 20:32:44 -0600
committerRene Ae <aehtyb@gmail.com>2015-12-04 20:32:44 -0600
commit10efb0f7b426426057fed757fe3c851a249358dd (patch)
treeb80e285251d30fbca36220c932ef180c29c55dcf /StoneIsland/platforms/android/cordova/lib
parent015b58ff6845b5cb79b13fec109a37b4c10c7813 (diff)
android build
Diffstat (limited to 'StoneIsland/platforms/android/cordova/lib')
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/android_sdk_version.js64
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/appinfo.js41
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/build.js717
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/check_reqs.js327
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/device.js121
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/emulator.js372
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/exec.js68
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/install-device42
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/install-device.bat26
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/install-emulator38
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/install-emulator.bat26
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-devices33
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-devices.bat26
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-emulator-images32
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-emulator-images.bat26
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-started-emulators32
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/list-started-emulators.bat26
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/log.js56
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/plugin-build.gradle79
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/retry.js66
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/run.js160
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/spawn.js50
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/start-emulator39
-rwxr-xr-xStoneIsland/platforms/android/cordova/lib/start-emulator.bat26
24 files changed, 2493 insertions, 0 deletions
diff --git a/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js b/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js
new file mode 100755
index 00000000..79af2727
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js
@@ -0,0 +1,64 @@
+#!/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 child_process = require('child_process'),
+ Q = require('q');
+
+var get_highest_sdk = function(results){
+ var reg = /\d+/;
+ var apiLevels = [];
+ for(var i=0;i<results.length;i++){
+ apiLevels[i] = parseInt(results[i].match(reg)[0]);
+ }
+ apiLevels.sort(function(a,b){return b-a;});
+ console.log(apiLevels[0]);
+};
+
+var get_sdks = function() {
+ var d = Q.defer();
+ child_process.exec('android list targets', function(err, stdout, stderr) {
+ if (err) d.reject(stderr);
+ else d.resolve(stdout);
+ });
+
+ return d.promise.then(function(output) {
+ var reg = /android-\d+/gi;
+ var results = output.match(reg);
+ if(results.length===0){
+ return Q.reject(new Error('No android sdks installed.'));
+ }else{
+ get_highest_sdk(results);
+ }
+
+ return Q();
+ }, function(stderr) {
+ if (stderr.match(/command\snot\sfound/) || stderr.match(/'android' is not recognized/)) {
+ return Q.reject(new Error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.'));
+ } else {
+ return Q.reject(new Error('An error occurred while listing Android targets'));
+ }
+ });
+};
+
+module.exports.run = function() {
+ return Q.all([get_sdks()]);
+};
+
diff --git a/StoneIsland/platforms/android/cordova/lib/appinfo.js b/StoneIsland/platforms/android/cordova/lib/appinfo.js
new file mode 100755
index 00000000..080c2ba8
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/appinfo.js
@@ -0,0 +1,41 @@
+#!/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');
+var fs = require('fs');
+var cachedAppInfo = null;
+
+function readAppInfoFromManifest() {
+ var manifestPath = path.join(__dirname, '..', '..', 'AndroidManifest.xml');
+ var manifestData = fs.readFileSync(manifestPath, {encoding:'utf8'});
+ var packageName = /\bpackage\s*=\s*"(.+?)"/.exec(manifestData);
+ if (!packageName) throw new Error('Could not find package name within ' + manifestPath);
+ var activityTag = /<activity\b[\s\S]*<\/activity>/.exec(manifestData);
+ if (!activityTag) throw new Error('Could not find <activity> within ' + manifestPath);
+ var activityName = /\bandroid:name\s*=\s*"(.+?)"/.exec(activityTag);
+ if (!activityName) throw new Error('Could not find android:name within ' + manifestPath);
+
+ return packageName[1] + '/.' + activityName[1];
+}
+
+exports.getActivityName = function() {
+ return (cachedAppInfo = cachedAppInfo || readAppInfoFromManifest());
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/build.js b/StoneIsland/platforms/android/cordova/lib/build.js
new file mode 100755
index 00000000..aa9f3d01
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/build.js
@@ -0,0 +1,717 @@
+#!/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 shell = require('shelljs'),
+ spawn = require('./spawn'),
+ Q = require('q'),
+ path = require('path'),
+ fs = require('fs'),
+ os = require('os'),
+ ROOT = path.join(__dirname, '..', '..');
+var check_reqs = require('./check_reqs');
+var exec = require('./exec');
+
+
+var SIGNING_PROPERTIES = '-signing.properties';
+var MARKER = 'YOUR CHANGES WILL BE ERASED!';
+var TEMPLATE =
+ '# This file is automatically generated.\n' +
+ '# Do not modify this file -- ' + MARKER + '\n';
+
+function findApks(directory) {
+ var ret = [];
+ if (fs.existsSync(directory)) {
+ fs.readdirSync(directory).forEach(function(p) {
+ if (path.extname(p) == '.apk') {
+ ret.push(path.join(directory, p));
+ }
+ });
+ }
+ return ret;
+}
+
+function sortFilesByDate(files) {
+ return files.map(function(p) {
+ return { p: p, t: fs.statSync(p).mtime };
+ }).sort(function(a, b) {
+ var timeDiff = b.t - a.t;
+ return timeDiff === 0 ? a.p.length - b.p.length : timeDiff;
+ }).map(function(p) { return p.p; });
+}
+
+function isAutoGenerated(file) {
+ if(fs.existsSync(file)) {
+ var fileContents = fs.readFileSync(file, 'utf8');
+ return fileContents.indexOf(MARKER) > 0;
+ }
+ return false;
+}
+
+function findOutputApksHelper(dir, build_type, arch) {
+ var ret = findApks(dir).filter(function(candidate) {
+ // Need to choose between release and debug .apk.
+ if (build_type === 'debug') {
+ return /-debug/.exec(candidate) && !/-unaligned|-unsigned/.exec(candidate);
+ }
+ if (build_type === 'release') {
+ return /-release/.exec(candidate) && !/-unaligned/.exec(candidate);
+ }
+ return true;
+ });
+ ret = sortFilesByDate(ret);
+ if (ret.length === 0) {
+ return ret;
+ }
+ // Assume arch-specific build if newest apk has -x86 or -arm.
+ var archSpecific = !!/-x86|-arm/.exec(ret[0]);
+ // And show only arch-specific ones (or non-arch-specific)
+ ret = ret.filter(function(p) {
+ /*jshint -W018 */
+ return !!/-x86|-arm/.exec(p) == archSpecific;
+ /*jshint +W018 */
+ });
+ if (archSpecific && ret.length > 1) {
+ ret = ret.filter(function(p) {
+ return p.indexOf('-' + arch) != -1;
+ });
+ }
+
+ return ret;
+}
+
+function hasCustomRules() {
+ return fs.existsSync(path.join(ROOT, 'custom_rules.xml'));
+}
+
+function extractRealProjectNameFromManifest(projectPath) {
+ var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
+ var manifestData = fs.readFileSync(manifestPath, 'utf8');
+ var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
+ if (!m) {
+ throw new Error('Could not find package name in ' + manifestPath);
+ }
+
+ var packageName=m[1];
+ var lastDotIndex = packageName.lastIndexOf('.');
+ return packageName.substring(lastDotIndex + 1);
+}
+
+function extractProjectNameFromManifest(projectPath) {
+ var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
+ var manifestData = fs.readFileSync(manifestPath, 'utf8');
+ var m = /<activity[\s\S]*?android:name\s*=\s*"(.*?)"/i.exec(manifestData);
+ if (!m) {
+ throw new Error('Could not find activity name in ' + manifestPath);
+ }
+ return m[1];
+}
+
+function findAllUniq(data, r) {
+ var s = {};
+ var m;
+ while ((m = r.exec(data))) {
+ s[m[1]] = 1;
+ }
+ return Object.keys(s);
+}
+
+function readProjectProperties() {
+ var data = fs.readFileSync(path.join(ROOT, 'project.properties'), 'utf8');
+ return {
+ libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
+ gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
+ systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
+ };
+}
+
+var builders = {
+ ant: {
+ getArgs: function(cmd, opts) {
+ var args = [cmd, '-f', path.join(ROOT, 'build.xml')];
+ // custom_rules.xml is required for incremental builds.
+ if (hasCustomRules()) {
+ args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
+ }
+ if(opts.packageInfo) {
+ args.push('-propertyfile=' + path.join(ROOT, opts.buildType + SIGNING_PROPERTIES));
+ }
+ return args;
+ },
+
+ prepEnv: function(opts) {
+ return check_reqs.check_ant()
+ .then(function() {
+ // Copy in build.xml on each build so that:
+ // A) we don't require the Android SDK at project creation time, and
+ // B) we always use the SDK's latest version of it.
+ var sdkDir = process.env['ANDROID_HOME'];
+ var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
+ function writeBuildXml(projectPath) {
+ var newData = buildTemplate.replace('PROJECT_NAME', extractProjectNameFromManifest(ROOT));
+ fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
+ if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
+ fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
+ }
+ }
+ writeBuildXml(ROOT);
+ var propertiesObj = readProjectProperties();
+ var subProjects = propertiesObj.libs;
+ for (var i = 0; i < subProjects.length; ++i) {
+ writeBuildXml(path.join(ROOT, subProjects[i]));
+ }
+ if (propertiesObj.systemLibs.length > 0) {
+ throw new Error('Project contains at least one plugin that requires a system library. This is not supported with ANT. Please build using gradle.');
+ }
+
+ var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+ var propertiesFilePath = path.join(ROOT, propertiesFile);
+ if (opts.packageInfo) {
+ fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+ } else if(isAutoGenerated(propertiesFilePath)) {
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+ },
+
+ /*
+ * Builds the project with ant.
+ * Returns a promise.
+ */
+ build: function(opts) {
+ // Without our custom_rules.xml, we need to clean before building.
+ var ret = Q();
+ if (!hasCustomRules()) {
+ // clean will call check_ant() for us.
+ ret = this.clean(opts);
+ }
+
+ var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
+ return check_reqs.check_ant()
+ .then(function() {
+ console.log('Executing: ant ' + args.join(' '));
+ return spawn('ant', args);
+ });
+ },
+
+ clean: function(opts) {
+ var args = this.getArgs('clean', opts);
+ return check_reqs.check_ant()
+ .then(function() {
+ return spawn('ant', args);
+ });
+ },
+
+ findOutputApks: function(build_type) {
+ var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin');
+ return findOutputApksHelper(binDir, build_type, null);
+ }
+ },
+ gradle: {
+ getArgs: function(cmd, opts) {
+ if (cmd == 'release') {
+ cmd = 'cdvBuildRelease';
+ } else if (cmd == 'debug') {
+ cmd = 'cdvBuildDebug';
+ }
+ var args = [cmd, '-b', path.join(ROOT, 'build.gradle')];
+ if (opts.arch) {
+ args.push('-PcdvBuildArch=' + opts.arch);
+ }
+
+ // 10 seconds -> 6 seconds
+ args.push('-Dorg.gradle.daemon=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;
+ },
+
+ // Makes the project buildable, minus the gradle wrapper.
+ prepBuildFiles: function() {
+ var projectPath = ROOT;
+ // Update the version of build.gradle in each dependent library.
+ var pluginBuildGradle = path.join(projectPath, 'cordova', 'lib', 'plugin-build.gradle');
+ var propertiesObj = readProjectProperties();
+ var subProjects = propertiesObj.libs;
+ for (var i = 0; i < subProjects.length; ++i) {
+ if (subProjects[i] !== 'CordovaLib') {
+ shell.cp('-f', pluginBuildGradle, path.join(ROOT, subProjects[i], 'build.gradle'));
+ }
+ }
+
+ var name = extractRealProjectNameFromManifest(ROOT);
+ //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(projectPath, 'settings.gradle'),
+ '// GENERATED FILE - DO NOT EDIT\n' +
+ 'include ":"\n' + settingsGradlePaths.join(''));
+ // Update dependencies within build.gradle.
+ var buildGradle = fs.readFileSync(path.join(projectPath, 'build.gradle'), 'utf8');
+ var depsList = '';
+ subProjects.forEach(function(p) {
+ var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
+ depsList += ' debugCompile project(path: "' + libName + '", configuration: "debug")\n';
+ depsList += ' releaseCompile project(path: "' + libName + '", configuration: "release")\n';
+ });
+ // 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 Error('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(projectPath, 'build.gradle'), buildGradle);
+ },
+
+ prepEnv: function(opts) {
+ var self = this;
+ return check_reqs.check_gradle()
+ .then(function() {
+ return self.prepBuildFiles();
+ }).then(function() {
+ // Copy the gradle wrapper on each build so that:
+ // A) we don't require the Android SDK at project creation time, and
+ // B) we always use the SDK's latest version of it.
+ var projectPath = ROOT;
+ // check_reqs ensures that this is set.
+ var sdkDir = process.env['ANDROID_HOME'];
+ var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
+ if (process.platform == 'win32') {
+ shell.rm('-f', path.join(projectPath, 'gradlew.bat'));
+ shell.cp(path.join(wrapperDir, 'gradlew.bat'), projectPath);
+ } else {
+ shell.rm('-f', path.join(projectPath, 'gradlew'));
+ shell.cp(path.join(wrapperDir, 'gradlew'), projectPath);
+ }
+ shell.rm('-rf', path.join(projectPath, 'gradle', 'wrapper'));
+ shell.mkdir('-p', path.join(projectPath, 'gradle'));
+ shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(projectPath, '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/;
+ var distributionUrl = 'distributionUrl=http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
+ var gradleWrapperPropertiesPath = path.join(projectPath, 'gradle', 'wrapper', 'gradle-wrapper.properties');
+ shell.chmod('u+w', gradleWrapperPropertiesPath);
+ shell.sed('-i', distributionUrlRegex, distributionUrl, gradleWrapperPropertiesPath);
+
+ var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+ var propertiesFilePath = path.join(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.
+ */
+ build: function(opts) {
+ var wrapper = path.join(ROOT, 'gradlew');
+ var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
+ return Q().then(function() {
+ console.log('Running: ' + wrapper + ' ' + args.join(' '));
+ return spawn(wrapper, args);
+ });
+ },
+
+ clean: function(opts) {
+ var builder = this;
+ var wrapper = path.join(ROOT, 'gradlew');
+ var args = builder.getArgs('clean', opts);
+ return Q().then(function() {
+ console.log('Running: ' + wrapper + ' ' + args.join(' '));
+ return spawn(wrapper, args);
+ });
+ },
+
+ findOutputApks: function(build_type, arch) {
+ var binDir = path.join(ROOT, 'build', 'outputs', 'apk');
+ return findOutputApksHelper(binDir, build_type, arch);
+ }
+ },
+
+ none: {
+ prepEnv: function() {
+ return Q();
+ },
+ build: function() {
+ console.log('Skipping build...');
+ return Q(null);
+ },
+ clean: function() {
+ return Q();
+ },
+ findOutputApks: function(build_type, arch) {
+ return sortFilesByDate(builders.ant.findOutputApks(build_type, arch).concat(builders.gradle.findOutputApks(build_type, arch)));
+ }
+ }
+};
+
+module.exports.isBuildFlag = function(flag) {
+ return /^--(debug|release|ant|gradle|nobuild|versionCode=|minSdkVersion=|gradleArg=|keystore=|alias=|password=|storePassword=|keystoreType=|buildConfig=)/.exec(flag);
+};
+
+function parseOpts(options, resolvedTarget) {
+ // Backwards-compatibility: Allow a single string argument
+ if (typeof options == 'string') options = [options];
+
+ var ret = {
+ buildType: 'debug',
+ buildMethod: process.env['ANDROID_BUILD'] || 'gradle',
+ arch: null,
+ extraArgs: []
+ };
+
+ var multiValueArgs = {
+ 'versionCode': true,
+ 'minSdkVersion': true,
+ 'gradleArg': true,
+ 'keystore' : true,
+ 'alias' : true,
+ 'password' : true,
+ 'storePassword' : true,
+ 'keystoreType' : true,
+ 'buildConfig' : true
+ };
+ var packageArgs = {};
+ var buildConfig;
+ // Iterate through command line options
+ for (var i=0; options && (i < options.length); ++i) {
+ if (/^--/.exec(options[i])) {
+ var keyValue = options[i].substring(2).split('=');
+ var flagName = keyValue.shift();
+ var flagValue = keyValue.join('=');
+ if (multiValueArgs[flagName] && !flagValue) {
+ flagValue = options[i + 1];
+ ++i;
+ }
+ switch(flagName) {
+ case 'debug':
+ case 'release':
+ ret.buildType = flagName;
+ break;
+ case 'ant':
+ case 'gradle':
+ ret.buildMethod = flagName;
+ break;
+ case 'device':
+ case 'emulator':
+ // Don't need to do anything special to when building for device vs emulator.
+ // iOS uses this flag to switch on architecture.
+ break;
+ case 'prepenv' :
+ ret.prepEnv = true;
+ break;
+ case 'nobuild' :
+ ret.buildMethod = 'none';
+ break;
+ case 'versionCode':
+ ret.extraArgs.push('-PcdvVersionCode=' + flagValue);
+ break;
+ case 'minSdkVersion':
+ ret.extraArgs.push('-PcdvMinSdkVersion=' + flagValue);
+ break;
+ case 'gradleArg':
+ ret.extraArgs.push(flagValue);
+ break;
+ case 'keystore':
+ packageArgs.keystore = path.relative(ROOT, path.resolve(flagValue));
+ break;
+ case 'alias':
+ case 'storePassword':
+ case 'password':
+ case 'keystoreType':
+ packageArgs[flagName] = flagValue;
+ break;
+ case 'buildConfig':
+ buildConfig = flagValue;
+ break;
+ default :
+ console.warn('Build option --\'' + flagName + '\' not recognized (ignoring).');
+ }
+ } else {
+ console.warn('Build option \'' + options[i] + '\' not recognized (ignoring).');
+ }
+ }
+
+ // If some values are not specified as command line arguments - use build config to supplement them.
+ // Command line arguemnts have precedence over build config.
+ if (buildConfig) {
+ if (!fs.existsSync(buildConfig)) {
+ throw new Error('Specified build config file does not exist: ' + buildConfig);
+ }
+ console.log('Reading build config file: '+ path.resolve(buildConfig));
+ var config = JSON.parse(fs.readFileSync(buildConfig, 'utf8'));
+ if (config.android && config.android[ret.buildType]) {
+ var androidInfo = config.android[ret.buildType];
+ if(androidInfo.keystore && !packageArgs.keystore) {
+ if(path.isAbsolute(androidInfo.keystore)) {
+ packageArgs.keystore = androidInfo.keystore;
+ } else {
+ packageArgs.keystore = path.relative(ROOT, path.join(path.dirname(buildConfig), androidInfo.keystore));
+ }
+ }
+
+ ['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
+ packageArgs[key] = packageArgs[key] || androidInfo[key];
+ });
+ }
+ }
+ if (packageArgs.keystore && packageArgs.alias) {
+ ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
+ packageArgs.password, packageArgs.keystoreType);
+ }
+
+ if(!ret.packageInfo) {
+ if(Object.keys(packageArgs).length > 0) {
+ console.warn('\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
+ }
+ }
+ ret.arch = resolvedTarget && resolvedTarget.arch;
+
+ return ret;
+}
+
+/*
+ * Builds the project with the specifed options
+ * Returns a promise.
+ */
+module.exports.runClean = function(options) {
+ var opts = parseOpts(options);
+ var builder = builders[opts.buildMethod];
+ return builder.prepEnv(opts)
+ .then(function() {
+ return builder.clean(opts);
+ }).then(function() {
+ shell.rm('-rf', path.join(ROOT, 'out'));
+
+ ['debug', 'release'].forEach(function(config) {
+ var propertiesFilePath = path.join(ROOT, config + SIGNING_PROPERTIES);
+ if(isAutoGenerated(propertiesFilePath)){
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+ });
+};
+
+/*
+ * Builds the project with the specifed options
+ * Returns a promise.
+ */
+module.exports.run = function(options, optResolvedTarget) {
+ var opts = parseOpts(options, optResolvedTarget);
+ var builder = builders[opts.buildMethod];
+ return builder.prepEnv(opts)
+ .then(function() {
+ if (opts.prepEnv) {
+ console.log('Build file successfully prepared.');
+ return;
+ }
+ return builder.build(opts)
+ .then(function() {
+ var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
+ console.log('Built the following apk(s):');
+ console.log(' ' + apkPaths.join('\n '));
+ return {
+ apkPaths: apkPaths,
+ buildType: opts.buildType,
+ buildMethod: opts.buildMethod
+ };
+ });
+ });
+};
+
+// Called by plugman after installing plugins, and by create script after creating project.
+module.exports.prepBuildFiles = function() {
+ var builder = builders['gradle'];
+ return builder.prepBuildFiles();
+};
+
+/*
+ * Detects the architecture of a device/emulator
+ * Returns "arm" or "x86".
+ */
+module.exports.detectArchitecture = function(target) {
+ function helper() {
+ return exec('adb -s ' + target + ' shell cat /proc/cpuinfo', os.tmpdir())
+ .then(function(output) {
+ if (/intel/i.exec(output)) {
+ return 'x86';
+ }
+ return 'arm';
+ });
+ }
+ // It sometimes happens (at least on OS X), that this command will hang forever.
+ // To fix it, either unplug & replug device, or restart adb server.
+ return helper().timeout(1000, 'Device communication timed out. Try unplugging & replugging the device.')
+ .then(null, function(err) {
+ if (/timed out/.exec('' + err)) {
+ // 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 exec('killall adb')
+ .then(function() {
+ console.log('adb seems hung. retrying.');
+ return helper()
+ .then(null, function() {
+ // The double kill is sadly often necessary, at least on mac.
+ console.log('Now device not found... restarting adb again.');
+ return exec('killall adb')
+ .then(function() {
+ return helper()
+ .then(null, function() {
+ return Q.reject('USB is flakey. Try unplugging & replugging the device.');
+ });
+ });
+ });
+ }, function() {
+ // For non-killall OS's.
+ return Q.reject(err);
+ });
+ }
+ throw err;
+ });
+};
+
+module.exports.findBestApkForArchitecture = function(buildResults, arch) {
+ var paths = buildResults.apkPaths.filter(function(p) {
+ if (buildResults.buildType == 'debug') {
+ return /-debug/.exec(p);
+ }
+ return !/-debug/.exec(p);
+ });
+ var archPattern = new RegExp('-' + arch);
+ var hasArchPattern = /-x86|-arm/;
+ for (var i = 0; i < paths.length; ++i) {
+ if (hasArchPattern.exec(paths[i])) {
+ if (archPattern.exec(paths[i])) {
+ return paths[i];
+ }
+ } else {
+ return paths[i];
+ }
+ }
+ throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
+};
+
+function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
+ this.keystore = {
+ 'name': 'key.store',
+ 'value': keystore
+ };
+ this.alias = {
+ 'name': 'key.alias',
+ 'value': alias
+ };
+ if (storePassword) {
+ this.storePassword = {
+ 'name': 'key.store.password',
+ 'value': storePassword
+ };
+ }
+ if (password) {
+ this.password = {
+ 'name': 'key.alias.password',
+ 'value': password
+ };
+ }
+ if (keystoreType) {
+ this.keystoreType = {
+ 'name': 'key.store.type',
+ 'value': keystoreType
+ };
+ }
+}
+
+PackageInfo.prototype = {
+ toProperties: function() {
+ var self = this;
+ var result = '';
+ Object.keys(self).forEach(function(key) {
+ result += self[key].name;
+ result += '=';
+ result += self[key].value.replace(/\\/g, '\\\\');
+ result += '\n';
+ });
+ return result;
+ }
+};
+
+module.exports.help = function() {
+ console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [flags] [Signed APK flags]');
+ console.log('Flags:');
+ console.log(' \'--debug\': will build project in debug mode (default)');
+ console.log(' \'--release\': will build project for release');
+ console.log(' \'--ant\': will build project with ant');
+ console.log(' \'--gradle\': will build project with gradle (default)');
+ console.log(' \'--nobuild\': will skip build process (useful when using run command)');
+ console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
+ console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
+ console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
+ console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
+ console.log('');
+ console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
+ console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
+ console.log(' \'--alias=\': Alias for the key store. (Required)');
+ console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
+ console.log(' \'--password=\': Password for the key. (Optional - prompted)');
+ console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
+ process.exit(0);
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/check_reqs.js b/StoneIsland/platforms/android/cordova/lib/check_reqs.js
new file mode 100755
index 00000000..9d251596
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/check_reqs.js
@@ -0,0 +1,327 @@
+#!/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'),
+ which = require('which'),
+ ROOT = path.join(__dirname, '..', '..');
+
+var isWindows = process.platform == 'win32';
+
+function forgivingWhichSync(cmd) {
+ try {
+ // TODO: Should use shelljs.which() here to have one less dependency.
+ return fs.realpathSync(which.sync(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 Error(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;
+}
+
+// Get valid target from framework/project.properties
+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();
+ }
+ if (fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
+ return extractFromFile(path.join(ROOT, 'framework', 'project.properties'));
+ }
+ if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
+ // if no target found, we're probably in a project and project.properties is in ROOT.
+ return extractFromFile(path.join(ROOT, 'project.properties'));
+ }
+ throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_ant = function() {
+ return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
+ .then(function (output) {
+ // Parse Ant version from command output
+ return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
+ });
+};
+
+// Returns a promise. Called only by build and clean commands.
+module.exports.check_gradle = function() {
+ var sdkDir = process.env['ANDROID_HOME'];
+ if (!sdkDir)
+ return Q.reject('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 wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
+ if (!fs.existsSync(wrapperDir)) {
+ return Q.reject(new Error('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
+ 'Looked here: ' + wrapperDir));
+ }
+ return Q.when();
+};
+
+// 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) {
+ var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
+ // OS X has a command for finding JAVA_HOME.
+ if (fs.existsSync('/usr/libexec/java_home')) {
+ return tryCommand('/usr/libexec/java_home', msg)
+ .then(function(stdout) {
+ process.env['JAVA_HOME'] = stdout.trim();
+ });
+ } 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 Error(msg);
+ }
+ }
+ } else if (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 "java -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';
+ }
+ return tryCommand('java -version', msg)
+ .then(function() {
+ // 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) {
+ var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
+ 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 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;
+ }
+ }
+ if (!hasAndroidHome && !androidCmdPath) {
+ if (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 (process.platform == 'darwin') {
+ // 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 && !androidCmdPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
+ }
+ if (androidCmdPath && !hasAndroidHome) {
+ var parentDir = path.dirname(androidCmdPath);
+ var grandParentDir = path.dirname(parentDir);
+ if (path.basename(parentDir) == 'tools') {
+ process.env['ANDROID_HOME'] = path.dirname(parentDir);
+ hasAndroidHome = true;
+ } else if (fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
+ process.env['ANDROID_HOME'] = grandParentDir;
+ hasAndroidHome = true;
+ } else {
+ throw new Error('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 path to valid SDK directory.');
+ }
+ }
+ if (hasAndroidHome && !adbInPath) {
+ process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
+ }
+ if (!process.env['ANDROID_HOME']) {
+ throw new Error('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 Error('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
+ '\nTry update it manually to point to valid SDK directory.');
+ }
+ });
+};
+
+module.exports.getAbsoluteAndroidCmd = function() {
+ return forgivingWhichSync('android').replace(/(\s)/g, '\\$1');
+};
+
+module.exports.check_android_target = function(valid_target) {
+ // valid_target can look like:
+ // android-19
+ // android-L
+ // Google Inc.:Google APIs:20
+ // Google Inc.:Glass Development Kit Preview:20
+ if (!valid_target) valid_target = module.exports.get_target();
+ var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
+ return tryCommand('android list targets --compact', msg)
+ .then(function(output) {
+ var targets = output.split('\n');
+ if (targets.indexOf(valid_target) >= 0) {
+ return targets;
+ }
+
+ var androidCmd = module.exports.getAbsoluteAndroidCmd();
+ throw new Error('Please install Android target: "' + valid_target + '".\n\n' +
+ 'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
+ 'You will require:\n' +
+ '1. "SDK Platform" for ' + valid_target + '\n' +
+ '2. "Android SDK Platform-tools (latest)\n' +
+ '3. "Android SDK Build-tools" (latest)');
+ });
+};
+
+// Returns a promise.
+module.exports.run = function() {
+ return Q.all([this.check_java(), this.check_android().then(this.check_android_target)])
+ .then(function() {
+ console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
+ console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
+ });
+};
+
+/**
+ * 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;
+ });
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/device.js b/StoneIsland/platforms/android/cordova/lib/device.js
new file mode 100755
index 00000000..c13fdc40
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/device.js
@@ -0,0 +1,121 @@
+#!/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 exec = require('./exec'),
+ Q = require('q'),
+ os = require('os'),
+ build = require('./build'),
+ appinfo = require('./appinfo');
+
+/**
+ * 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) {
+ function helper() {
+ return exec('adb devices', os.tmpdir())
+ .then(function(output) {
+ var response = output.split('\n');
+ var device_list = [];
+ for (var i = 1; i < response.length; i++) {
+ if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
+ device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+ }
+ }
+ return device_list;
+ });
+ }
+ return helper()
+ .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 exec('killall adb')
+ .then(function() {
+ console.log('Restarting adb to see if more devices are detected.');
+ return helper();
+ }, 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('ERROR: 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 launchName = appinfo.getActivityName();
+ console.log('Using apk: ' + apk_path);
+ console.log('Installing app on device...');
+ var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
+ return exec(cmd, os.tmpdir())
+ .then(function(output) {
+ if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
+
+ //unlock screen
+ var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
+ return exec(cmd, os.tmpdir());
+ }, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
+ .then(function() {
+ // launch the application
+ console.log('Launching application...');
+ var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
+ return exec(cmd, os.tmpdir());
+ }).then(function() {
+ console.log('LAUNCH SUCCESS');
+ }, function(err) {
+ return Q.reject('ERROR: Failed to launch application on device: ' + err);
+ });
+ });
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/emulator.js b/StoneIsland/platforms/android/cordova/lib/emulator.js
new file mode 100755
index 00000000..e81dd679
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/emulator.js
@@ -0,0 +1,372 @@
+#!/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 exec = require('./exec');
+var appinfo = require('./appinfo');
+var retry = require('./retry');
+var build = require('./build');
+var check_reqs = require('./check_reqs');
+
+var Q = require('q');
+var os = require('os');
+var child_process = require('child_process');
+
+// constants
+var ONE_SECOND = 1000; // in milliseconds
+var INSTALL_COMMAND_TIMEOUT = 120 * ONE_SECOND; // in milliseconds
+var NUM_INSTALL_RETRIES = 3;
+var EXEC_KILL_SIGNAL = 'SIGKILL';
+
+/**
+ * Returns a Promise for a list of emulator images in the form of objects
+ * {
+ name : <emulator_name>,
+ path : <path_to_emulator_image>,
+ target : <api_target>,
+ abi : <cpu>,
+ skin : <skin>
+ }
+ */
+module.exports.list_images = function() {
+ return exec('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(/Path:\s/)) {
+ i++;
+ img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+ }
+ if (response[i + 1].match(/\(API\slevel\s/)) {
+ i++;
+ img_obj['target'] = response[i].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;
+ });
+};
+
+/**
+ * Will return the closest avd to the projects target
+ * or undefined if no avds exist.
+ * Returns a promise.
+ */
+module.exports.best_image = function() {
+ var project_target = check_reqs.get_target().replace('android-', '');
+ return this.list_images()
+ .then(function(images) {
+ var closest = 9999;
+ var best = images[0];
+ 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 exec('adb devices', os.tmpdir())
+ .then(function(output) {
+ var response = output.split('\n');
+ var started_emulator_list = [];
+ for (var i = 1; i < response.length; i++) {
+ if (response[i].match(/device/) && response[i].match(/emulator/)) {
+ started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+ }
+ }
+ return started_emulator_list;
+ });
+};
+
+// Returns a promise.
+module.exports.list_targets = function() {
+ return exec('android list targets', 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;
+ });
+};
+
+/*
+ * Starts an emulator with the given ID,
+ * and returns the started ID of that emulator.
+ * If no ID is given it will used the first image available,
+ * if no image is available it will error out (maybe create one?).
+ *
+ * Returns a promise.
+ */
+module.exports.start = function(emulator_ID) {
+ var self = this;
+ var emulator_id, num_started, started_emulators;
+
+ return self.list_started()
+ .then(function(list) {
+ started_emulators = list;
+ num_started = started_emulators.length;
+ if (!emulator_ID) {
+ return self.list_images()
+ .then(function(emulator_list) {
+ if (emulator_list.length > 0) {
+ return self.best_image()
+ .then(function(best) {
+ emulator_ID = best.name;
+ console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
+ return emulator_ID;
+ });
+ } else {
+ var androidCmd = check_reqs.getAbsoluteAndroidCmd();
+ return Q.reject('ERROR : 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');
+ }
+ });
+ } else {
+ return Q(emulator_ID);
+ }
+ }).then(function() {
+ var cmd = 'emulator';
+ var args = ['-avd', emulator_ID];
+ var proc = child_process.spawn(cmd, args, { stdio: 'inherit', detached: true });
+ proc.unref(); // Don't wait for it to finish, since the emulator will probably keep running for a long time.
+ }).then(function() {
+ // wait for emulator to start
+ console.log('Waiting for emulator...');
+ return self.wait_for_emulator(num_started);
+ }).then(function(new_started) {
+ if (new_started.length > 1) {
+ for (var i in new_started) {
+ if (started_emulators.indexOf(new_started[i]) < 0) {
+ emulator_id = new_started[i];
+ }
+ }
+ } else {
+ emulator_id = new_started[0];
+ }
+ if (!emulator_id) return Q.reject('ERROR : Failed to start emulator, could not find new emulator');
+
+ //wait for emulator to boot up
+ process.stdout.write('Booting up emulator (this may take a while)...');
+ return self.wait_for_boot(emulator_id);
+ }).then(function() {
+ console.log('BOOT COMPLETE');
+
+ //unlock screen
+ return exec('adb -s ' + emulator_id + ' shell input keyevent 82', os.tmpdir());
+ }).then(function() {
+ //return the new emulator id for the started emulators
+ return emulator_id;
+ });
+};
+
+/*
+ * Waits for the new emulator to apear on the started-emulator list.
+ * Returns a promise with a list of newly started emulators' IDs.
+ */
+module.exports.wait_for_emulator = function(num_running) {
+ var self = this;
+ return self.list_started()
+ .then(function(new_started) {
+ if (new_started.length > num_running) {
+ return new_started;
+ } else {
+ return Q.delay(1000).then(function() {
+ return self.wait_for_emulator(num_running);
+ });
+ }
+ });
+};
+
+/*
+ * Waits for the boot animation property of the emulator to switch to 'stopped'
+ */
+module.exports.wait_for_boot = function(emulator_id) {
+ var self = this;
+ return exec('adb -s ' + emulator_id + ' shell getprop init.svc.bootanim', os.tmpdir())
+ .then(function(output) {
+ if (output.match(/stopped/)) {
+ return;
+ } else {
+ process.stdout.write('.');
+ return Q.delay(3000).then(function() {
+ return self.wait_for_boot(emulator_id);
+ });
+ }
+ });
+};
+
+/*
+ * 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 avd named ' + name);
+ if (target) {
+ return exec('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 exec('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('Please insure 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 started emulators found, please start an emultor 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;
+
+ // 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 () {
+
+ var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
+ var execOptions = {
+ timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
+ killSignal: EXEC_KILL_SIGNAL
+ };
+
+ console.log('Installing app on emulator...');
+ console.log('Using apk: ' + apk_path);
+
+ var retriedInstall = retry.retryPromise(
+ NUM_INSTALL_RETRIES,
+ exec, 'adb -s ' + target.target + ' install -r -d "' + apk_path + '"', os.tmpdir(), execOptions
+ );
+
+ return retriedInstall.then(function (output) {
+ if (output.match(/Failure/)) {
+ return Q.reject('Failed to install apk to emulator: ' + output);
+ } else {
+ console.log('INSTALL SUCCESS');
+ }
+ }, function (err) {
+ return Q.reject('Failed to install apk to emulator: ' + err);
+ });
+
+ // unlock screen
+ }).then(function () {
+
+ console.log('Unlocking screen...');
+ return exec('adb -s ' + target.target + ' shell input keyevent 82', os.tmpdir());
+
+ // launch the application
+ }).then(function () {
+
+ console.log('Launching application...');
+ var launchName = appinfo.getActivityName();
+ var cmd = 'adb -s ' + target.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
+ return exec(cmd, os.tmpdir());
+
+ // report success or failure
+ }).then(function (output) {
+ console.log('LAUNCH SUCCESS');
+ }, function (err) {
+ return Q.reject('Failed to launch app on emulator: ' + err);
+ });
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/exec.js b/StoneIsland/platforms/android/cordova/lib/exec.js
new file mode 100755
index 00000000..798a93ba
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/exec.js
@@ -0,0 +1,68 @@
+#!/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 child_process = require("child_process");
+var Q = require("q");
+
+// constants
+var DEFAULT_MAX_BUFFER = 1024000;
+
+// Takes a command and optional current working directory.
+// Returns a promise that either resolves with the stdout, or
+// rejects with an error message and the stderr.
+//
+// WARNING:
+// opt_cwd is an artifact of an old design, and must
+// be removed in the future; the correct solution is
+// to pass the options object the same way that
+// child_process.exec expects
+//
+// NOTE:
+// exec documented here - https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
+module.exports = function(cmd, opt_cwd, options) {
+
+ var d = Q.defer();
+
+ if (typeof options === "undefined") {
+ options = {};
+ }
+
+ // override cwd to preserve old opt_cwd behavior
+ options.cwd = opt_cwd;
+
+ // set maxBuffer
+ if (typeof options.maxBuffer === "undefined") {
+ options.maxBuffer = DEFAULT_MAX_BUFFER;
+ }
+
+ try {
+ child_process.exec(cmd, options, function(err, stdout, stderr) {
+ if (err) d.reject("Error executing \"" + cmd + "\": " + stderr);
+ else d.resolve(stdout);
+ });
+ } catch(e) {
+ console.error("error caught: " + e);
+ d.reject(e);
+ }
+
+ return d.promise;
+};
+
diff --git a/StoneIsland/platforms/android/cordova/lib/install-device b/StoneIsland/platforms/android/cordova/lib/install-device
new file mode 100755
index 00000000..fc4b7841
--- /dev/null
+++ b/StoneIsland/platforms/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);
+ });
+}
diff --git a/StoneIsland/platforms/android/cordova/lib/install-device.bat b/StoneIsland/platforms/android/cordova/lib/install-device.bat
new file mode 100755
index 00000000..ac7214ac
--- /dev/null
+++ b/StoneIsland/platforms/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
diff --git a/StoneIsland/platforms/android/cordova/lib/install-emulator b/StoneIsland/platforms/android/cordova/lib/install-emulator
new file mode 100755
index 00000000..aa2a34f6
--- /dev/null
+++ b/StoneIsland/platforms/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);
+});
diff --git a/StoneIsland/platforms/android/cordova/lib/install-emulator.bat b/StoneIsland/platforms/android/cordova/lib/install-emulator.bat
new file mode 100755
index 00000000..1ec67790
--- /dev/null
+++ b/StoneIsland/platforms/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
diff --git a/StoneIsland/platforms/android/cordova/lib/list-devices b/StoneIsland/platforms/android/cordova/lib/list-devices
new file mode 100755
index 00000000..e390bff6
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/list-devices
@@ -0,0 +1,33 @@
+#!/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
+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);
+});
+
diff --git a/StoneIsland/platforms/android/cordova/lib/list-devices.bat b/StoneIsland/platforms/android/cordova/lib/list-devices.bat
new file mode 100755
index 00000000..c0bcdd9a
--- /dev/null
+++ b/StoneIsland/platforms/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
diff --git a/StoneIsland/platforms/android/cordova/lib/list-emulator-images b/StoneIsland/platforms/android/cordova/lib/list-emulator-images
new file mode 100755
index 00000000..996cf555
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/list-emulator-images
@@ -0,0 +1,32 @@
+#!/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
+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);
+});
diff --git a/StoneIsland/platforms/android/cordova/lib/list-emulator-images.bat b/StoneIsland/platforms/android/cordova/lib/list-emulator-images.bat
new file mode 100755
index 00000000..661cbf95
--- /dev/null
+++ b/StoneIsland/platforms/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
+)
diff --git a/StoneIsland/platforms/android/cordova/lib/list-started-emulators b/StoneIsland/platforms/android/cordova/lib/list-started-emulators
new file mode 100755
index 00000000..2ae8c5a8
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/list-started-emulators
@@ -0,0 +1,32 @@
+#!/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
+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);
+});
diff --git a/StoneIsland/platforms/android/cordova/lib/list-started-emulators.bat b/StoneIsland/platforms/android/cordova/lib/list-started-emulators.bat
new file mode 100755
index 00000000..a4e88f7d
--- /dev/null
+++ b/StoneIsland/platforms/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
diff --git a/StoneIsland/platforms/android/cordova/lib/log.js b/StoneIsland/platforms/android/cordova/lib/log.js
new file mode 100755
index 00000000..ebf836d5
--- /dev/null
+++ b/StoneIsland/platforms/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);
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/plugin-build.gradle b/StoneIsland/platforms/android/cordova/lib/plugin-build.gradle
new file mode 100755
index 00000000..b345b90a
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/plugin-build.gradle
@@ -0,0 +1,79 @@
+/* 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()
+ }
+
+ // 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
+ if (gradle.gradleVersion >= "2.2") {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.0.0+'
+ }
+ } else if (gradle.gradleVersion >= "2.1") {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.14.0+'
+ }
+ } else {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.12.0+'
+ }
+ }
+}
+
+apply plugin: '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'
+}
diff --git a/StoneIsland/platforms/android/cordova/lib/retry.js b/StoneIsland/platforms/android/cordova/lib/retry.js
new file mode 100755
index 00000000..dc52a7d2
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/retry.js
@@ -0,0 +1,66 @@
+#!/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 node: true */
+
+"use strict";
+
+/*
+ * Retry a promise-returning function a number of times, propagating its
+ * results on success or throwing its error on a failed final attempt.
+ *
+ * @arg {Number} attemts_left - The number of times to retry the passed call.
+ * @arg {Function} promiseFunction - A function that returns a promise.
+ * @arg {...} - Arguments to pass to promiseFunction.
+ *
+ * @returns {Promise}
+ */
+module.exports.retryPromise = function (attemts_left, promiseFunction) {
+
+ // NOTE:
+ // get all trailing arguments, by skipping the first two (attemts_left and
+ // promiseFunction) because they shouldn't get passed to promiseFunction
+ var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
+
+ return promiseFunction.apply(undefined, promiseFunctionArguments).then(
+
+ // on success pass results through
+ function onFulfilled(value) {
+ return value;
+ },
+
+ // on rejection either retry, or throw the error
+ function onRejected(error) {
+
+ attemts_left -= 1;
+
+ if (attemts_left < 1) {
+ throw error;
+ }
+
+ console.log("A retried call failed. Retrying " + attemts_left + " more time(s).");
+
+ // retry call self again with the same arguments, except attemts_left is now lower
+ var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
+ return module.exports.retryPromise.apply(undefined, fullArguments);
+ }
+ );
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/run.js b/StoneIsland/platforms/android/cordova/lib/run.js
new file mode 100755
index 00000000..7f15448c
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/run.js
@@ -0,0 +1,160 @@
+#!/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 loopfunc:true */
+
+var path = require('path'),
+ build = require('./build'),
+ emulator = require('./emulator'),
+ device = require('./device'),
+ shell = require('shelljs'),
+ Q = require('q');
+
+/*
+ * Runs the application on a device if available.
+ * If no device is found, it will use a started emulator.
+ * If no started emulators are found it will attempt to start an avd.
+ * If no avds are found it will error out.
+ * Returns a promise.
+ */
+ module.exports.run = function(args) {
+ var buildFlags = [];
+ var install_target;
+ var list = false;
+
+ for (var i=2; i<args.length; i++) {
+ if (build.isBuildFlag(args[i])) {
+ buildFlags.push(args[i]);
+ } else if (args[i] == '--device') {
+ install_target = '--device';
+ } else if (args[i] == '--emulator') {
+ install_target = '--emulator';
+ } else if (/^--target=/.exec(args[i])) {
+ install_target = args[i].substring(9, args[i].length);
+ } else if (args[i] == '--list') {
+ list = true;
+ } else {
+ console.warn('Option \'' + args[i] + '\' not recognized (ignoring).');
+ }
+ }
+
+ if (list) {
+ var output = '';
+ var temp = '';
+ if (!install_target) {
+ output += 'Available Android Devices:\n';
+ temp = shell.exec(path.join(__dirname, 'list-devices'), {silent:true}).output;
+ temp = temp.replace(/^(?=[^\s])/gm, '\t');
+ output += temp;
+ output += 'Available Android Virtual Devices:\n';
+ temp = shell.exec(path.join(__dirname, 'list-emulator-images'), {silent:true}).output;
+ temp = temp.replace(/^(?=[^\s])/gm, '\t');
+ output += temp;
+ } else if (install_target == '--emulator') {
+ output += 'Available Android Virtual Devices:\n';
+ temp = shell.exec(path.join(__dirname, 'list-emulator-images'), {silent:true}).output;
+ temp = temp.replace(/^(?=[^\s])/gm, '\t');
+ output += temp;
+ } else if (install_target == '--device') {
+ output += 'Available Android Devices:\n';
+ temp = shell.exec(path.join(__dirname, 'list-devices'), {silent:true}).output;
+ temp = temp.replace(/^(?=[^\s])/gm, '\t');
+ output += temp;
+ }
+ console.log(output);
+ return;
+ }
+
+ return Q()
+ .then(function() {
+ if (!install_target) {
+ // no target given, deploy to device if available, otherwise use the emulator.
+ return device.list()
+ .then(function(device_list) {
+ if (device_list.length > 0) {
+ console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
+ install_target = device_list[0];
+ } else {
+ console.log('WARNING : No target specified, deploying to emulator');
+ install_target = '--emulator';
+ }
+ });
+ }
+ }).then(function() {
+ if (install_target == '--device') {
+ return device.resolveTarget(null);
+ } else if (install_target == '--emulator') {
+ // Give preference to any already started emulators. Else, start one.
+ return emulator.list_started()
+ .then(function(started) {
+ return started && started.length > 0 ? started[0] : emulator.start();
+ }).then(function(emulatorId) {
+ return emulator.resolveTarget(emulatorId);
+ });
+ }
+ // They specified a specific device/emulator ID.
+ return device.list()
+ .then(function(devices) {
+ if (devices.indexOf(install_target) > -1) {
+ return device.resolveTarget(install_target);
+ }
+ return emulator.list_started()
+ .then(function(started_emulators) {
+ if (started_emulators.indexOf(install_target) > -1) {
+ return emulator.resolveTarget(install_target);
+ }
+ return emulator.list_images()
+ .then(function(avds) {
+ // if target emulator isn't started, then start it.
+ for (var avd in avds) {
+ if (avds[avd].name == install_target) {
+ return emulator.start(install_target)
+ .then(function(emulatorId) {
+ return emulator.resolveTarget(emulatorId);
+ });
+ }
+ }
+ return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
+ });
+ });
+ });
+ }).then(function(resolvedTarget) {
+ return build.run(buildFlags, resolvedTarget).then(function(buildResults) {
+ if (resolvedTarget.isEmulator) {
+ return emulator.install(resolvedTarget, buildResults);
+ }
+ return device.install(resolvedTarget, buildResults);
+ });
+ });
+};
+
+module.exports.help = function(args) {
+ console.log('Usage: ' + path.relative(process.cwd(), args[1]) + ' [options]');
+ console.log('Build options :');
+ console.log(' --debug : Builds project in debug mode');
+ console.log(' --release : Builds project in release mode');
+ console.log(' --nobuild : Runs the currently built project without recompiling');
+ console.log('Deploy options :');
+ console.log(' --device : Will deploy the built project to a device');
+ console.log(' --emulator : Will deploy the built project to an emulator if one exists');
+ console.log(' --target=<target_id> : Installs to the target with the specified id.');
+ process.exit(0);
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/spawn.js b/StoneIsland/platforms/android/cordova/lib/spawn.js
new file mode 100755
index 00000000..3e500a09
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/spawn.js
@@ -0,0 +1,50 @@
+#!/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 child_process = require('child_process'),
+ Q = require('q');
+var isWindows = process.platform.slice(0, 3) == 'win';
+
+// Takes a command and optional current working directory.
+module.exports = function(cmd, args, opt_cwd) {
+ var d = Q.defer();
+ var opts = { cwd: opt_cwd, stdio: 'inherit' };
+ try {
+ // Work around spawn not being able to find .bat files.
+ if (isWindows) {
+ args = [['/s', '/c', '"' + [cmd].concat(args).map(function(a){if (/^[^"].* .*[^"]/.test(a)) return '"' + a + '"'; return a;}).join(' ')+'"'].join(' ')];
+ cmd = 'cmd';
+ opts.windowsVerbatimArguments = true;
+ }
+ var child = child_process.spawn(cmd, args, opts);
+ child.on('exit', function(code) {
+ if (code) {
+ d.reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args);
+ } else {
+ d.resolve();
+ }
+ });
+ } catch(e) {
+ console.error('error caught: ' + e);
+ d.reject(e);
+ }
+ return d.promise;
+};
diff --git a/StoneIsland/platforms/android/cordova/lib/start-emulator b/StoneIsland/platforms/android/cordova/lib/start-emulator
new file mode 100755
index 00000000..f96bdc3e
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/start-emulator
@@ -0,0 +1,39 @@
+#!/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.start(install_target).done(null, function(err) {
+ console.error('ERROR: ' + err);
+ process.exit(2);
+});
+
diff --git a/StoneIsland/platforms/android/cordova/lib/start-emulator.bat b/StoneIsland/platforms/android/cordova/lib/start-emulator.bat
new file mode 100755
index 00000000..9329d951
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/start-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="%~dp0start-emulator"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2
+ EXIT /B 1
+) \ No newline at end of file