You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2015/10/21 01:16:12 UTC

[1/4] android commit: Fixed line endings

Repository: cordova-android
Updated Branches:
  refs/heads/master 400282282 -> 0ac822c57


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/emulator.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js
index 3233502..9e214b1 100644
--- a/bin/templates/cordova/lib/emulator.js
+++ b/bin/templates/cordova/lib/emulator.js
@@ -1,372 +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 retry      = require('./retry');
-var build      = require('./build');
-var check_reqs = require('./check_reqs');
-var path = require('path');
-var Adb = require('./Adb');
-var AndroidManifest = require('./AndroidManifest');
-var events = require('cordova-common').events;
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-
-var Q             = require('q');
-var os            = require('os');
-var child_process = require('child_process');
-
-// constants
-var ONE_SECOND              = 1000; // in milliseconds
-var ONE_MINUTE              = 60 * ONE_SECOND; // in milliseconds
-var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
-var NUM_INSTALL_RETRIES     = 3;
-var 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 spawn('android', ['list', 'avds'])
-    .then(function(output) {
-        var response = output.split('\n');
-        var emulator_list = [];
-        for (var i = 1; i < response.length; i++) {
-            // To return more detailed information use img_obj
-            var img_obj = {};
-            if (response[i].match(/Name:\s/)) {
-                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
-                if (response[i + 1].match(/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() {
-    return this.list_images()
-    .then(function(images) {
-        // Just return undefined if there is no images
-        if (images.length === 0) return;
-
-        var closest = 9999;
-        var best = images[0];
-        var project_target = check_reqs.get_target().replace('android-', '');
-        for (var i in images) {
-            var target = images[i].target;
-            if(target) {
-                var num = target.split('(API level ')[1].replace(')', '');
-                if (num == project_target) {
-                    return images[i];
-                } else if (project_target - num < closest && project_target > num) {
-                    closest = project_target - num;
-                    best = images[i];
-                }
-            }
-        }
-        return best;
-    });
-};
-
-// Returns a promise.
-module.exports.list_started = function() {
-    return Adb.devices({emulators: true});
-};
-
-// Returns a promise.
-module.exports.list_targets = function() {
-    return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
-    .then(function(output) {
-        var target_out = output.split('\n');
-        var targets = [];
-        for (var i = target_out.length; i >= 0; i--) {
-            if(target_out[i].match(/id:/)) {
-                targets.push(targets[i].split(' ')[1]);
-            }
-        }
-        return targets;
-    });
-};
-
-/*
- * Starts an emulator with the given ID,
- * and returns the started ID of that emulator.
- * If no ID is given it will use the first image available,
- * if no image is available it will error out (maybe create one?).
- *
- * Returns a promise.
- */
-module.exports.start = function(emulator_ID) {
-    var self = this;
-
-    return Q().then(function() {
-        if (emulator_ID) return Q(emulator_ID);
-
-        return self.best_image()
-        .then(function(best) {
-            if (best && best.name) {
-                events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
-                return best.name;
-            }
-
-            var androidCmd = check_reqs.getAbsoluteAndroidCmd();
-            return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
-                '1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
-                '2. Create an AVD by running: ' + androidCmd + ' avd\n' +
-                'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
-        });
-    }).then(function(emulatorId) {
-        var uuid = 'cordova_emulator_' + new Date().getTime();
-        var uuidProp = 'emu.uuid=' + uuid;
-        var args = ['-avd', emulatorId, '-prop', uuidProp];
-        // Don't wait for it to finish, since the emulator will probably keep running for a long time.
-        child_process
-            .spawn('emulator', args, { stdio: 'inherit', detached: true })
-            .unref();
-
-        // wait for emulator to start
-        events.emit('log', 'Waiting for emulator...');
-        return self.wait_for_emulator(uuid);
-    }).then(function(emulatorId) {
-        if (!emulatorId)
-            return Q.reject(new CordovaError('Failed to start emulator'));
-
-        //wait for emulator to boot up
-        process.stdout.write('Booting up emulator (this may take a while)...');
-        return self.wait_for_boot(emulatorId)
-        .then(function() {
-            events.emit('log','BOOT COMPLETE');
-            //unlock screen
-            return Adb.shell(emulatorId, 'input keyevent 82');
-        }).then(function() {
-            //return the new emulator id for the started emulators
-            return emulatorId;
-        });
-    });
-};
-
-/*
- * Waits for an emulator with given uuid to apear on the started-emulator list.
- * Returns a promise with this emulator's ID.
- */
-module.exports.wait_for_emulator = function(uuid) {
-    var self = this;
-    return self.list_started()
-    .then(function(new_started) {
-        var emulator_id = null;
-        var promises = [];
-
-        new_started.forEach(function (emulator) {
-            promises.push(
-                Adb.shell(emulator, 'getprop emu.uuid')
-                .then(function (output) {
-                    if (output.indexOf(uuid) >= 0) {
-                        emulator_id = emulator;
-                    }
-                })
-            );
-        });
-
-        return Q.all(promises).then(function () {
-            return emulator_id || self.wait_for_emulator(uuid);
-        });
-     });
-};
-
-/*
- * Waits for the core android process of the emulator to start
- */
-module.exports.wait_for_boot = function(emulator_id) {
-    var self = this;
-    return Adb.shell(emulator_id, 'ps')
-    .then(function(output) {
-        if (output.match(/android\.process\.acore/)) {
-            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 spawn('android', ['create', 'avd', '--name', name, '--target', target])
-        .then(null, function(error) {
-            console.error('ERROR : Failed to create emulator image : ');
-            console.error(' Do you have the latest android targets including ' + target + '?');
-            console.error(error);
-        });
-    } else {
-        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
-        return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
-        .then(function() {
-            // TODO: This seems like another error case, even though it always happens.
-            console.error('ERROR : Unable to create an avd emulator, no targets found.');
-            console.error('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;
-    var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
-    var pkgName = manifest.getPackageId();
-
-    // resolve the target emulator
-    return Q().then(function () {
-        if (givenTarget && typeof givenTarget == 'object') {
-            return givenTarget;
-        } else {
-            return module.exports.resolveTarget(givenTarget);
-        }
-
-    // set the resolved target
-    }).then(function (resolvedTarget) {
-        target = resolvedTarget;
-
-    // install the app
-    }).then(function () {
-        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
-        // or the app doesn't installed at all, so no error catching needed.
-        return Adb.uninstall(target.target, pkgName)
-        .then(function() {
-
-            var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
-            var execOptions = {
-                cwd: os.tmpdir(),
-                timeout:    INSTALL_COMMAND_TIMEOUT, // in milliseconds
-                killSignal: EXEC_KILL_SIGNAL
-            };
-
-            events.emit('log', 'Using apk: ' + apk_path);
-            events.emit('verbose', 'Installing app on emulator...');
-
-            function exec(command, opts) {
-                return Q.promise(function (resolve, reject) {
-                    child_process.exec(command, opts, function(err, stdout, stderr) {
-                        if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
-                        else resolve(stdout);
-                    });
-                });
-            }
-
-            var retriedInstall = retry.retryPromise(
-                NUM_INSTALL_RETRIES,
-                exec, 'adb -s ' + target.target + ' install -r "' + apk_path + '"', execOptions
-            );
-
-            return retriedInstall.then(function (output) {
-                if (output.match(/Failure/)) {
-                    return Q.reject(new CordovaError('Failed to install apk to emulator: ' + output));
-                } else {
-                    events.emit('log', 'INSTALL SUCCESS');
-                }
-            }, function (err) {
-                return Q.reject(new CordovaError('Failed to install apk to emulator: ' + err));
-            });
-        });
-    // unlock screen
-    }).then(function () {
-
-        events.emit('verbose', 'Unlocking screen...');
-        return Adb.shell(target.target, 'input keyevent 82');
-    }).then(function () {
-        Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
-    // report success or failure
-    }).then(function (output) {
-        events.emit('log', 'LAUNCH SUCCESS');
-    });
-};
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+/* jshint sub:true */
+
+var retry      = require('./retry');
+var build      = require('./build');
+var check_reqs = require('./check_reqs');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+var Q             = require('q');
+var os            = require('os');
+var child_process = require('child_process');
+
+// constants
+var ONE_SECOND              = 1000; // in milliseconds
+var ONE_MINUTE              = 60 * ONE_SECOND; // in milliseconds
+var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
+var NUM_INSTALL_RETRIES     = 3;
+var 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 spawn('android', ['list', 'avds'])
+    .then(function(output) {
+        var response = output.split('\n');
+        var emulator_list = [];
+        for (var i = 1; i < response.length; i++) {
+            // To return more detailed information use img_obj
+            var img_obj = {};
+            if (response[i].match(/Name:\s/)) {
+                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+                if (response[i + 1].match(/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() {
+    return this.list_images()
+    .then(function(images) {
+        // Just return undefined if there is no images
+        if (images.length === 0) return;
+
+        var closest = 9999;
+        var best = images[0];
+        var project_target = check_reqs.get_target().replace('android-', '');
+        for (var i in images) {
+            var target = images[i].target;
+            if(target) {
+                var num = target.split('(API level ')[1].replace(')', '');
+                if (num == project_target) {
+                    return images[i];
+                } else if (project_target - num < closest && project_target > num) {
+                    closest = project_target - num;
+                    best = images[i];
+                }
+            }
+        }
+        return best;
+    });
+};
+
+// Returns a promise.
+module.exports.list_started = function() {
+    return Adb.devices({emulators: true});
+};
+
+// Returns a promise.
+module.exports.list_targets = function() {
+    return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
+    .then(function(output) {
+        var target_out = output.split('\n');
+        var targets = [];
+        for (var i = target_out.length; i >= 0; i--) {
+            if(target_out[i].match(/id:/)) {
+                targets.push(targets[i].split(' ')[1]);
+            }
+        }
+        return targets;
+    });
+};
+
+/*
+ * Starts an emulator with the given ID,
+ * and returns the started ID of that emulator.
+ * If no ID is given it will use the first image available,
+ * if no image is available it will error out (maybe create one?).
+ *
+ * Returns a promise.
+ */
+module.exports.start = function(emulator_ID) {
+    var self = this;
+
+    return Q().then(function() {
+        if (emulator_ID) return Q(emulator_ID);
+
+        return self.best_image()
+        .then(function(best) {
+            if (best && best.name) {
+                events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
+                return best.name;
+            }
+
+            var androidCmd = check_reqs.getAbsoluteAndroidCmd();
+            return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
+                '1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
+                '2. Create an AVD by running: ' + androidCmd + ' avd\n' +
+                'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
+        });
+    }).then(function(emulatorId) {
+        var uuid = 'cordova_emulator_' + new Date().getTime();
+        var uuidProp = 'emu.uuid=' + uuid;
+        var args = ['-avd', emulatorId, '-prop', uuidProp];
+        // Don't wait for it to finish, since the emulator will probably keep running for a long time.
+        child_process
+            .spawn('emulator', args, { stdio: 'inherit', detached: true })
+            .unref();
+
+        // wait for emulator to start
+        events.emit('log', 'Waiting for emulator...');
+        return self.wait_for_emulator(uuid);
+    }).then(function(emulatorId) {
+        if (!emulatorId)
+            return Q.reject(new CordovaError('Failed to start emulator'));
+
+        //wait for emulator to boot up
+        process.stdout.write('Booting up emulator (this may take a while)...');
+        return self.wait_for_boot(emulatorId)
+        .then(function() {
+            events.emit('log','BOOT COMPLETE');
+            //unlock screen
+            return Adb.shell(emulatorId, 'input keyevent 82');
+        }).then(function() {
+            //return the new emulator id for the started emulators
+            return emulatorId;
+        });
+    });
+};
+
+/*
+ * Waits for an emulator with given uuid to apear on the started-emulator list.
+ * Returns a promise with this emulator's ID.
+ */
+module.exports.wait_for_emulator = function(uuid) {
+    var self = this;
+    return self.list_started()
+    .then(function(new_started) {
+        var emulator_id = null;
+        var promises = [];
+
+        new_started.forEach(function (emulator) {
+            promises.push(
+                Adb.shell(emulator, 'getprop emu.uuid')
+                .then(function (output) {
+                    if (output.indexOf(uuid) >= 0) {
+                        emulator_id = emulator;
+                    }
+                })
+            );
+        });
+
+        return Q.all(promises).then(function () {
+            return emulator_id || self.wait_for_emulator(uuid);
+        });
+     });
+};
+
+/*
+ * Waits for the core android process of the emulator to start
+ */
+module.exports.wait_for_boot = function(emulator_id) {
+    var self = this;
+    return Adb.shell(emulator_id, 'ps')
+    .then(function(output) {
+        if (output.match(/android\.process\.acore/)) {
+            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 spawn('android', ['create', 'avd', '--name', name, '--target', target])
+        .then(null, function(error) {
+            console.error('ERROR : Failed to create emulator image : ');
+            console.error(' Do you have the latest android targets including ' + target + '?');
+            console.error(error);
+        });
+    } else {
+        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
+        return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
+        .then(function() {
+            // TODO: This seems like another error case, even though it always happens.
+            console.error('ERROR : Unable to create an avd emulator, no targets found.');
+            console.error('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;
+    var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
+    var pkgName = manifest.getPackageId();
+
+    // resolve the target emulator
+    return Q().then(function () {
+        if (givenTarget && typeof givenTarget == 'object') {
+            return givenTarget;
+        } else {
+            return module.exports.resolveTarget(givenTarget);
+        }
+
+    // set the resolved target
+    }).then(function (resolvedTarget) {
+        target = resolvedTarget;
+
+    // install the app
+    }).then(function () {
+        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+        // or the app doesn't installed at all, so no error catching needed.
+        return Adb.uninstall(target.target, pkgName)
+        .then(function() {
+
+            var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
+            var execOptions = {
+                cwd: os.tmpdir(),
+                timeout:    INSTALL_COMMAND_TIMEOUT, // in milliseconds
+                killSignal: EXEC_KILL_SIGNAL
+            };
+
+            events.emit('log', 'Using apk: ' + apk_path);
+            events.emit('verbose', 'Installing app on emulator...');
+
+            function exec(command, opts) {
+                return Q.promise(function (resolve, reject) {
+                    child_process.exec(command, opts, function(err, stdout, stderr) {
+                        if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
+                        else resolve(stdout);
+                    });
+                });
+            }
+
+            var retriedInstall = retry.retryPromise(
+                NUM_INSTALL_RETRIES,
+                exec, 'adb -s ' + target.target + ' install -r "' + apk_path + '"', execOptions
+            );
+
+            return retriedInstall.then(function (output) {
+                if (output.match(/Failure/)) {
+                    return Q.reject(new CordovaError('Failed to install apk to emulator: ' + output));
+                } else {
+                    events.emit('log', 'INSTALL SUCCESS');
+                }
+            }, function (err) {
+                return Q.reject(new CordovaError('Failed to install apk to emulator: ' + err));
+            });
+        });
+    // unlock screen
+    }).then(function () {
+
+        events.emit('verbose', 'Unlocking screen...');
+        return Adb.shell(target.target, 'input keyevent 82');
+    }).then(function () {
+        Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
+    // report success or failure
+    }).then(function (output) {
+        events.emit('log', 'LAUNCH SUCCESS');
+    });
+};

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/pluginHandlers.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js
index cad95c2..381734d 100644
--- a/bin/templates/cordova/lib/pluginHandlers.js
+++ b/bin/templates/cordova/lib/pluginHandlers.js
@@ -1,252 +1,252 @@
-/*
- *
- * Copyright 2013 Anis Kadri
- *
- * Licensed 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 unused: vars */
-
-var fs = require('fs');
-var path = require('path');
-var shell = require('shelljs');
-var events = require('cordova-common').events;
-var CordovaError = require('cordova-common').CordovaError;
-
-var handlers = {
-    'source-file':{
-        install:function(obj, plugin, project, options) {
-            if (!obj.src) throw new CordovaError('<source-file> element is missing "src" attribute for plugin: ' + plugin.id);
-            if (!obj.targetDir) throw new CordovaError('<source-file> element is missing "target-dir" attribute for plugin: ' + plugin.id);
-            var dest = path.join(obj.targetDir, path.basename(obj.src));
-            copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
-        },
-        uninstall:function(obj, plugin, project, options) {
-            var dest = path.join(obj.targetDir, path.basename(obj.src));
-            deleteJava(project.projectDir, dest);
-        }
-    },
-    'lib-file':{
-        install:function(obj, plugin, project, options) {
-            var dest = path.join('libs', path.basename(obj.src));
-            copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
-        },
-        uninstall:function(obj, plugin, project, options) {
-            var dest = path.join('libs', path.basename(obj.src));
-            removeFile(project.projectDir, dest);
-        }
-    },
-    'resource-file':{
-        install:function(obj, plugin, project, options) {
-            copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link);
-        },
-        uninstall:function(obj, plugin, project, options) {
-            removeFile(project.projectDir, path.normalize(obj.target));
-        }
-    },
-    'framework': {
-        install:function(obj, plugin, project, options) {
-            var src = obj.src;
-            if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
-
-            events.emit('verbose', 'Installing Android library: ' + src);
-            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
-            var subDir;
-
-            if (obj.custom) {
-                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
-                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link);
-                subDir = path.resolve(project.projectDir, subRelativeDir);
-            } else {
-                obj.type = 'sys';
-                subDir = src;
-            }
-
-            if (obj.type == 'gradleReference') {
-                project.addGradleReference(parentDir, subDir);
-            } else if (obj.type == 'sys') {
-                project.addSystemLibrary(parentDir, subDir);
-            } else {
-                project.addSubProject(parentDir, subDir);
-            }
-        },
-        uninstall:function(obj, plugin, project, options) {
-            var src = obj.src;
-            if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
-
-            events.emit('verbose', 'Uninstalling Android library: ' + src);
-            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
-            var subDir;
-
-            if (obj.custom) {
-                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
-                removeFile(project.projectDir, subRelativeDir);
-                subDir = path.resolve(project.projectDir, subRelativeDir);
-                // If it's the last framework in the plugin, remove the parent directory.
-                var parDir = path.dirname(subDir);
-                if (fs.readdirSync(parDir).length === 0) {
-                    fs.rmdirSync(parDir);
-                }
-            } else {
-                obj.type = 'sys';
-                subDir = src;
-            }
-
-            if (obj.type == 'gradleReference') {
-                project.removeGradleReference(parentDir, subDir);
-            } else if (obj.type == 'sys') {
-                project.removeSystemLibrary(parentDir, subDir);
-            } else {
-                project.removeSubProject(parentDir, subDir);
-            }
-        }
-    },
-    asset:{
-        install:function(obj, plugin, project, options) {
-            if (!obj.src) {
-                throw new CordovaError('<asset> tag without required "src" attribute. plugin=' + plugin.dir);
-            }
-            if (!obj.target) {
-                throw new CordovaError('<asset> tag without required "target" attribute');
-            }
-
-            var www = options.usePlatformWww ? project.platformWww : project.www;
-            copyFile(plugin.dir, obj.src, www, obj.target);
-        },
-        uninstall:function(obj, plugin, project, options) {
-            var target = obj.target || obj.src;
-
-            if (!target) throw new CordovaError('<asset> tag without required "target" attribute');
-
-            var www = options.usePlatformWww ? project.platformWww : project.www;
-            removeFile(www, target);
-            removeFileF(path.resolve(www, 'plugins', plugin.id));
-        }
-    },
-    'js-module': {
-        install: function (obj, plugin, project, options) {
-            // Copy the plugin's files into the www directory.
-            var moduleSource = path.resolve(plugin.dir, obj.src);
-            var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name);
-
-            // Read in the file, prepend the cordova.define, and write it back out.
-            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
-            if (moduleSource.match(/.*\.json$/)) {
-                scriptContent = 'module.exports = ' + scriptContent;
-            }
-            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
-
-            var www = options.usePlatformWww ? project.platformWww : project.www;
-            var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src);
-            shell.mkdir('-p', path.dirname(moduleDestination));
-            fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
-        },
-        uninstall: function (obj, plugin, project, options) {
-            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
-            var www = options.usePlatformWww ? project.platformWww : project.www;
-            removeFileAndParents(www, pluginRelativePath);
-        }
-    }
-};
-
-module.exports.getInstaller = function (type) {
-    if (handlers[type] && handlers[type].install) {
-        return handlers[type].install;
-    }
-
-    events.emit('verbose', '<' + type + '> is not supported for android plugins');
-};
-
-module.exports.getUninstaller = function(type) {
-    if (handlers[type] && handlers[type].uninstall) {
-        return handlers[type].uninstall;
-    }
-
-    events.emit('verbose', '<' + type + '> is not supported for android plugins');
-};
-
-function copyFile (plugin_dir, src, project_dir, dest, link) {
-    src = path.resolve(plugin_dir, src);
-    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
-
-    // check that src path is inside plugin directory
-    var real_path = fs.realpathSync(src);
-    var real_plugin_path = fs.realpathSync(plugin_dir);
-    if (real_path.indexOf(real_plugin_path) !== 0)
-        throw new CordovaError('"' + src + '" not located within plugin!');
-
-    dest = path.resolve(project_dir, dest);
-
-    // check that dest path is located in project directory
-    if (dest.indexOf(project_dir) !== 0)
-        throw new CordovaError('"' + dest + '" not located within project!');
-
-    shell.mkdir('-p', path.dirname(dest));
-
-    if (link) {
-        fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
-    } else if (fs.statSync(src).isDirectory()) {
-        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
-        shell.cp('-Rf', src+'/*', dest);
-    } else {
-        shell.cp('-f', src, dest);
-    }
-}
-
-// Same as copy file but throws error if target exists
-function copyNewFile (plugin_dir, src, project_dir, dest, link) {
-    var target_path = path.resolve(project_dir, dest);
-    if (fs.existsSync(target_path))
-        throw new CordovaError('"' + target_path + '" already exists!');
-
-    copyFile(plugin_dir, src, project_dir, dest, !!link);
-}
-
-// checks if file exists and then deletes. Error if doesn't exist
-function removeFile (project_dir, src) {
-    var file = path.resolve(project_dir, src);
-    shell.rm('-Rf', file);
-}
-
-// deletes file/directory without checking
-function removeFileF (file) {
-    shell.rm('-Rf', file);
-}
-
-// Sometimes we want to remove some java, and prune any unnecessary empty directories
-function deleteJava (project_dir, destFile) {
-    removeFileAndParents(project_dir, destFile, 'src');
-}
-
-function removeFileAndParents (baseDir, destFile, stopper) {
-    stopper = stopper || '.';
-    var file = path.resolve(baseDir, destFile);
-    if (!fs.existsSync(file)) return;
-
-    removeFileF(file);
-
-    // check if directory is empty
-    var curDir = path.dirname(file);
-
-    while(curDir !== path.resolve(baseDir, stopper)) {
-        if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
-            fs.rmdirSync(curDir);
-            curDir = path.resolve(curDir, '..');
-        } else {
-            // directory not empty...do nothing
-            break;
-        }
-    }
-}
+/*
+ *
+ * Copyright 2013 Anis Kadri
+ *
+ * Licensed 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 unused: vars */
+
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
+var handlers = {
+    'source-file':{
+        install:function(obj, plugin, project, options) {
+            if (!obj.src) throw new CordovaError('<source-file> element is missing "src" attribute for plugin: ' + plugin.id);
+            if (!obj.targetDir) throw new CordovaError('<source-file> element is missing "target-dir" attribute for plugin: ' + plugin.id);
+            var dest = path.join(obj.targetDir, path.basename(obj.src));
+            copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var dest = path.join(obj.targetDir, path.basename(obj.src));
+            deleteJava(project.projectDir, dest);
+        }
+    },
+    'lib-file':{
+        install:function(obj, plugin, project, options) {
+            var dest = path.join('libs', path.basename(obj.src));
+            copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var dest = path.join('libs', path.basename(obj.src));
+            removeFile(project.projectDir, dest);
+        }
+    },
+    'resource-file':{
+        install:function(obj, plugin, project, options) {
+            copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link);
+        },
+        uninstall:function(obj, plugin, project, options) {
+            removeFile(project.projectDir, path.normalize(obj.target));
+        }
+    },
+    'framework': {
+        install:function(obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
+
+            events.emit('verbose', 'Installing Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link);
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type == 'gradleReference') {
+                project.addGradleReference(parentDir, subDir);
+            } else if (obj.type == 'sys') {
+                project.addSystemLibrary(parentDir, subDir);
+            } else {
+                project.addSubProject(parentDir, subDir);
+            }
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
+
+            events.emit('verbose', 'Uninstalling Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                removeFile(project.projectDir, subRelativeDir);
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+                // If it's the last framework in the plugin, remove the parent directory.
+                var parDir = path.dirname(subDir);
+                if (fs.readdirSync(parDir).length === 0) {
+                    fs.rmdirSync(parDir);
+                }
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type == 'gradleReference') {
+                project.removeGradleReference(parentDir, subDir);
+            } else if (obj.type == 'sys') {
+                project.removeSystemLibrary(parentDir, subDir);
+            } else {
+                project.removeSubProject(parentDir, subDir);
+            }
+        }
+    },
+    asset:{
+        install:function(obj, plugin, project, options) {
+            if (!obj.src) {
+                throw new CordovaError('<asset> tag without required "src" attribute. plugin=' + plugin.dir);
+            }
+            if (!obj.target) {
+                throw new CordovaError('<asset> tag without required "target" attribute');
+            }
+
+            var www = options.usePlatformWww ? project.platformWww : project.www;
+            copyFile(plugin.dir, obj.src, www, obj.target);
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var target = obj.target || obj.src;
+
+            if (!target) throw new CordovaError('<asset> tag without required "target" attribute');
+
+            var www = options.usePlatformWww ? project.platformWww : project.www;
+            removeFile(www, target);
+            removeFileF(path.resolve(www, 'plugins', plugin.id));
+        }
+    },
+    'js-module': {
+        install: function (obj, plugin, project, options) {
+            // Copy the plugin's files into the www directory.
+            var moduleSource = path.resolve(plugin.dir, obj.src);
+            var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name);
+
+            // Read in the file, prepend the cordova.define, and write it back out.
+            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+            if (moduleSource.match(/.*\.json$/)) {
+                scriptContent = 'module.exports = ' + scriptContent;
+            }
+            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
+
+            var www = options.usePlatformWww ? project.platformWww : project.www;
+            var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src);
+            shell.mkdir('-p', path.dirname(moduleDestination));
+            fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
+            var www = options.usePlatformWww ? project.platformWww : project.www;
+            removeFileAndParents(www, pluginRelativePath);
+        }
+    }
+};
+
+module.exports.getInstaller = function (type) {
+    if (handlers[type] && handlers[type].install) {
+        return handlers[type].install;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+module.exports.getUninstaller = function(type) {
+    if (handlers[type] && handlers[type].uninstall) {
+        return handlers[type].uninstall;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+function copyFile (plugin_dir, src, project_dir, dest, link) {
+    src = path.resolve(plugin_dir, src);
+    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
+
+    // check that src path is inside plugin directory
+    var real_path = fs.realpathSync(src);
+    var real_plugin_path = fs.realpathSync(plugin_dir);
+    if (real_path.indexOf(real_plugin_path) !== 0)
+        throw new CordovaError('"' + src + '" not located within plugin!');
+
+    dest = path.resolve(project_dir, dest);
+
+    // check that dest path is located in project directory
+    if (dest.indexOf(project_dir) !== 0)
+        throw new CordovaError('"' + dest + '" not located within project!');
+
+    shell.mkdir('-p', path.dirname(dest));
+
+    if (link) {
+        fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
+    } else if (fs.statSync(src).isDirectory()) {
+        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
+        shell.cp('-Rf', src+'/*', dest);
+    } else {
+        shell.cp('-f', src, dest);
+    }
+}
+
+// Same as copy file but throws error if target exists
+function copyNewFile (plugin_dir, src, project_dir, dest, link) {
+    var target_path = path.resolve(project_dir, dest);
+    if (fs.existsSync(target_path))
+        throw new CordovaError('"' + target_path + '" already exists!');
+
+    copyFile(plugin_dir, src, project_dir, dest, !!link);
+}
+
+// checks if file exists and then deletes. Error if doesn't exist
+function removeFile (project_dir, src) {
+    var file = path.resolve(project_dir, src);
+    shell.rm('-Rf', file);
+}
+
+// deletes file/directory without checking
+function removeFileF (file) {
+    shell.rm('-Rf', file);
+}
+
+// Sometimes we want to remove some java, and prune any unnecessary empty directories
+function deleteJava (project_dir, destFile) {
+    removeFileAndParents(project_dir, destFile, 'src');
+}
+
+function removeFileAndParents (baseDir, destFile, stopper) {
+    stopper = stopper || '.';
+    var file = path.resolve(baseDir, destFile);
+    if (!fs.existsSync(file)) return;
+
+    removeFileF(file);
+
+    // check if directory is empty
+    var curDir = path.dirname(file);
+
+    while(curDir !== path.resolve(baseDir, stopper)) {
+        if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
+            fs.rmdirSync(curDir);
+            curDir = path.resolve(curDir, '..');
+        } else {
+            // directory not empty...do nothing
+            break;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/prepare.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js
index 67ac174..a514c8c 100644
--- a/bin/templates/cordova/lib/prepare.js
+++ b/bin/templates/cordova/lib/prepare.js
@@ -1,364 +1,364 @@
-/**
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-
-var Q = require('q');
-var fs = require('fs');
-var path = require('path');
-var shell = require('shelljs');
-var events = require('cordova-common').events;
-var AndroidManifest = require('./AndroidManifest');
-var xmlHelpers = require('cordova-common').xmlHelpers;
-var CordovaError = require('cordova-common').CordovaError;
-var ConfigParser = require('cordova-common').ConfigParser;
-
-module.exports.prepare = function (cordovaProject) {
-
-    var self = this;
-
-    this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
-        this._munger, this.locations);
-
-    // Update own www dir with project's www assets and plugins' assets and js-files
-    return Q.when(updateWwwFrom(cordovaProject, this.locations))
-    .then(function () {
-        // update project according to config.xml changes.
-        return updateProjectAccordingTo(self._config, self.locations);
-    })
-    .then(function () {
-        handleIcons(cordovaProject.projectConfig, self.root);
-        handleSplashes(cordovaProject.projectConfig, self.root);
-    })
-    .then(function () {
-        self.events.emit('verbose', 'updated project successfully');
-    });
-};
-
-/**
- * Updates config files in project based on app's config.xml and config munge,
- *   generated by plugins.
- *
- * @param   {ConfigParser}   sourceConfig  A project's configuration that will
- *   be merged into platform's config.xml
- * @param   {ConfigChanges}  configMunger  An initialized ConfigChanges instance
- *   for this platform.
- * @param   {Object}         locations     A map of locations for this platform
- *
- * @return  {ConfigParser}                 An instance of ConfigParser, that
- *   represents current project's configuration. When returned, the
- *   configuration is already dumped to appropriate config.xml file.
- */
-function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
-    events.emit('verbose', 'Generating config.xml from defaults for platform "android"');
-
-    // First cleanup current config and merge project's one into own
-    // Overwrite platform config.xml with defaults.xml.
-    shell.cp('-f', locations.defaultConfigXml, locations.configXml);
-
-    // Then apply config changes from global munge to all config files
-    // in project (including project's config)
-    configMunger.reapply_global_munge().save_all();
-
-    // Merge changes from app's config.xml into platform's one
-    var config = new ConfigParser(locations.configXml);
-    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
-        config.doc.getroot(), 'android', /*clobber=*/true);
-
-    config.write();
-    return config;
-}
-
-/**
- * Updates platform 'www' directory by replacing it with contents of
- *   'platform_www' and app www. Also copies project's overrides' folder into
- *   the platform 'www' folder
- *
- * @param   {Object}  cordovaProject    An object which describes cordova project.
- * @param   {Object}  destinations      An object that contains destination
- *   paths for www files.
- */
-function updateWwwFrom(cordovaProject, destinations) {
-    shell.rm('-rf', destinations.www);
-    shell.mkdir('-p', destinations.www);
-    // Copy source files from project's www directory
-    shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
-    // Override www sources by files in 'platform_www' directory
-    shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
-
-    // If project contains 'merges' for our platform, use them as another overrides
-    var merges_path = path.join(cordovaProject.root, 'merges', 'android');
-    if (fs.existsSync(merges_path)) {
-        events.emit('verbose', 'Found "merges" for android platform. Copying over existing "www" files.');
-        var overrides = path.join(merges_path, '*');
-        shell.cp('-rf', overrides, destinations.www);
-    }
-}
-
-/**
- * Updates project structure and AndroidManifest according to project's configuration.
- *
- * @param   {ConfigParser}  platformConfig  A project's configuration that will
- *   be used to update project
- * @param   {Object}  locations       A map of locations for this platform
- */
-function updateProjectAccordingTo(platformConfig, locations) {
-    // Update app name by editing res/values/strings.xml
-    var name = platformConfig.name();
-    var strings = xmlHelpers.parseElementtreeSync(locations.strings);
-    strings.find('string[@name="app_name"]').text = name;
-    fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
-    events.emit('verbose', 'Wrote out Android application name to "' + name + '"');
-
-    // Java packages cannot support dashes
-    var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
-
-    var manifest = new AndroidManifest(locations.manifest);
-    var orig_pkg = manifest.getPackageId();
-
-    manifest.getActivity()
-        .setOrientation(findOrientationValue(platformConfig))
-        .setLaunchMode(findAndroidLaunchModePreference(platformConfig));
-
-    manifest.setVersionName(platformConfig.version())
-        .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
-        .setPackageId(pkg)
-        .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
-        .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
-        .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
-        .write();
-
-    var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
-    var java_files = shell.ls(javaPattern).filter(function(f) {
-        return shell.grep(/extends\s+CordovaActivity/g, f);
-    });
-
-    if (java_files.length === 0) {
-        throw new CordovaError('No Java files found which extend CordovaActivity.');
-    } else if(java_files.length > 1) {
-        events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
-    }
-
-    var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
-    shell.mkdir('-p', path.dirname(destFile));
-    shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
-    events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
-}
-
-
-// Consturct the default value for versionCode as
-// PATCH + MINOR * 100 + MAJOR * 10000
-// see http://developer.android.com/tools/publishing/versioning.html
-function default_versionCode(version) {
-    var nums = version.split('-')[0].split('.');
-    var versionCode = 0;
-    if (+nums[0]) {
-        versionCode += +nums[0] * 10000;
-    }
-    if (+nums[1]) {
-        versionCode += +nums[1] * 100;
-    }
-    if (+nums[2]) {
-        versionCode += +nums[2];
-    }
-    return versionCode;
-}
-
-function copyImage(src, resourcesDir, density, name) {
-    var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
-    var isNinePatch = !!/\.9\.png$/.exec(src);
-    var ninePatchName = name.replace(/\.png$/, '.9.png');
-
-    // default template does not have default asset for this density
-    if (!fs.existsSync(destFolder)) {
-        fs.mkdirSync(destFolder);
-    }
-
-    var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
-    events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
-    shell.cp('-f', src, destFilePath);
-}
-
-function handleSplashes(projectConfig, platformRoot) {
-    var resources = projectConfig.getSplashScreens('android');
-    // if there are "splash" elements in config.xml
-    if (resources.length > 0) {
-        deleteDefaultResourceAt(platformRoot, 'screen.png');
-        events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
-
-        // The source paths for icons and splashes are relative to
-        // project's config.xml location, so we use it as base path.
-        var projectRoot = path.dirname(projectConfig.path);
-        var destination = path.join(platformRoot, 'res');
-
-        var hadMdpi = false;
-        resources.forEach(function (resource) {
-            if (!resource.density) {
-                return;
-            }
-            if (resource.density == 'mdpi') {
-                hadMdpi = true;
-            }
-            copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
-        });
-        // There's no "default" drawable, so assume default == mdpi.
-        if (!hadMdpi && resources.defaultResource) {
-            copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
-        }
-    }
-}
-
-function handleIcons(projectConfig, platformRoot) {
-    var icons = projectConfig.getIcons('android');
-
-    // if there are icon elements in config.xml
-    if (icons.length === 0) {
-        events.emit('verbose', 'This app does not have launcher icons defined');
-        return;
-    }
-
-    deleteDefaultResourceAt(platformRoot, 'icon.png');
-
-    var android_icons = {};
-    var default_icon;
-    // http://developer.android.com/design/style/iconography.html
-    var sizeToDensityMap = {
-        36: 'ldpi',
-        48: 'mdpi',
-        72: 'hdpi',
-        96: 'xhdpi',
-        144: 'xxhdpi',
-        192: 'xxxhdpi'
-    };
-    // find the best matching icon for a given density or size
-    // @output android_icons
-    var parseIcon = function(icon, icon_size) {
-        // do I have a platform icon for that density already
-        var density = icon.density || sizeToDensityMap[icon_size];
-        if (!density) {
-            // invalid icon defition ( or unsupported size)
-            return;
-        }
-        var previous = android_icons[density];
-        if (previous && previous.platform) {
-            return;
-        }
-        android_icons[density] = icon;
-    };
-
-    // iterate over all icon elements to find the default icon and call parseIcon
-    for (var i=0; i<icons.length; i++) {
-        var icon = icons[i];
-        var size = icon.width;
-        if (!size) {
-            size = icon.height;
-        }
-        if (!size && !icon.density) {
-            if (default_icon) {
-                events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
-            } else {
-                default_icon = icon;
-            }
-        } else {
-            parseIcon(icon, size);
-        }
-    }
-
-    // The source paths for icons and splashes are relative to
-    // project's config.xml location, so we use it as base path.
-    var projectRoot = path.dirname(projectConfig.path);
-    var destination = path.join(platformRoot, 'res');
-    for (var density in android_icons) {
-        copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
-    }
-    // There's no "default" drawable, so assume default == mdpi.
-    if (default_icon && !android_icons.mdpi) {
-        copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
-    }
-}
-
-// remove the default resource name from all drawable folders
-function deleteDefaultResourceAt(baseDir, resourceName) {
-    shell.ls(path.join(baseDir, 'res/drawable-*'))
-    .forEach(function (drawableFolder) {
-        var imagePath = path.join(drawableFolder, resourceName);
-        shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
-        events.emit('verbose', 'Deleted ' + imagePath);
-    });
-}
-
-/**
- * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
- *   preference value and warns if it doesn't seems to be valid
- *
- * @param   {ConfigParser}  platformConfig  A configParser instance for
- *   platform.
- *
- * @return  {String}                  Preference's value from config.xml or
- *   default value, if there is no such preference. The default value is
- *   'singleTop'
- */
-function findAndroidLaunchModePreference(platformConfig) {
-    var launchMode = platformConfig.getPreference('AndroidLaunchMode');
-    if (!launchMode) {
-        // Return a default value
-        return 'singleTop';
-    }
-
-    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
-    var valid = expectedValues.indexOf(launchMode) >= 0;
-    if (!valid) {
-        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
-        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
-            launchMode + '. Expected values are: ' + expectedValues.join(', '));
-    }
-
-    return launchMode;
-}
-
-/**
- * Queries ConfigParser object for the orientation <preference> value. Warns if
- *   global preference value is not supported by platform.
- *
- * @param  {Object} platformConfig    ConfigParser object
- *
- * @return {String}           Global/platform-specific orientation in lower-case
- *   (or empty string if both are undefined).
- */
-function findOrientationValue(platformConfig) {
-
-    var ORIENTATION_DEFAULT = 'default';
-
-    var orientation = platformConfig.getPreference('orientation');
-    if (!orientation) {
-        return ORIENTATION_DEFAULT;
-    }
-
-    var GLOBAL_ORIENTATIONS = ['default', 'portrait','landscape'];
-    function isSupported(orientation) {
-        return GLOBAL_ORIENTATIONS.indexOf(orientation.toLowerCase()) >= 0;
-    }
-
-    // Check if the given global orientation is supported
-    if (orientation && isSupported(orientation)) {
-        return orientation;
-    }
-
-    events.emit('warn', 'Unsupported global orientation: ' + orientation +
-        '. Defaulting to value: ' + ORIENTATION_DEFAULT);
-    return ORIENTATION_DEFAULT;
-}
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var AndroidManifest = require('./AndroidManifest');
+var xmlHelpers = require('cordova-common').xmlHelpers;
+var CordovaError = require('cordova-common').CordovaError;
+var ConfigParser = require('cordova-common').ConfigParser;
+
+module.exports.prepare = function (cordovaProject) {
+
+    var self = this;
+
+    this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
+        this._munger, this.locations);
+
+    // Update own www dir with project's www assets and plugins' assets and js-files
+    return Q.when(updateWwwFrom(cordovaProject, this.locations))
+    .then(function () {
+        // update project according to config.xml changes.
+        return updateProjectAccordingTo(self._config, self.locations);
+    })
+    .then(function () {
+        handleIcons(cordovaProject.projectConfig, self.root);
+        handleSplashes(cordovaProject.projectConfig, self.root);
+    })
+    .then(function () {
+        self.events.emit('verbose', 'updated project successfully');
+    });
+};
+
+/**
+ * Updates config files in project based on app's config.xml and config munge,
+ *   generated by plugins.
+ *
+ * @param   {ConfigParser}   sourceConfig  A project's configuration that will
+ *   be merged into platform's config.xml
+ * @param   {ConfigChanges}  configMunger  An initialized ConfigChanges instance
+ *   for this platform.
+ * @param   {Object}         locations     A map of locations for this platform
+ *
+ * @return  {ConfigParser}                 An instance of ConfigParser, that
+ *   represents current project's configuration. When returned, the
+ *   configuration is already dumped to appropriate config.xml file.
+ */
+function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
+    events.emit('verbose', 'Generating config.xml from defaults for platform "android"');
+
+    // First cleanup current config and merge project's one into own
+    // Overwrite platform config.xml with defaults.xml.
+    shell.cp('-f', locations.defaultConfigXml, locations.configXml);
+
+    // Then apply config changes from global munge to all config files
+    // in project (including project's config)
+    configMunger.reapply_global_munge().save_all();
+
+    // Merge changes from app's config.xml into platform's one
+    var config = new ConfigParser(locations.configXml);
+    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+        config.doc.getroot(), 'android', /*clobber=*/true);
+
+    config.write();
+    return config;
+}
+
+/**
+ * Updates platform 'www' directory by replacing it with contents of
+ *   'platform_www' and app www. Also copies project's overrides' folder into
+ *   the platform 'www' folder
+ *
+ * @param   {Object}  cordovaProject    An object which describes cordova project.
+ * @param   {Object}  destinations      An object that contains destination
+ *   paths for www files.
+ */
+function updateWwwFrom(cordovaProject, destinations) {
+    shell.rm('-rf', destinations.www);
+    shell.mkdir('-p', destinations.www);
+    // Copy source files from project's www directory
+    shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
+    // Override www sources by files in 'platform_www' directory
+    shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
+
+    // If project contains 'merges' for our platform, use them as another overrides
+    var merges_path = path.join(cordovaProject.root, 'merges', 'android');
+    if (fs.existsSync(merges_path)) {
+        events.emit('verbose', 'Found "merges" for android platform. Copying over existing "www" files.');
+        var overrides = path.join(merges_path, '*');
+        shell.cp('-rf', overrides, destinations.www);
+    }
+}
+
+/**
+ * Updates project structure and AndroidManifest according to project's configuration.
+ *
+ * @param   {ConfigParser}  platformConfig  A project's configuration that will
+ *   be used to update project
+ * @param   {Object}  locations       A map of locations for this platform
+ */
+function updateProjectAccordingTo(platformConfig, locations) {
+    // Update app name by editing res/values/strings.xml
+    var name = platformConfig.name();
+    var strings = xmlHelpers.parseElementtreeSync(locations.strings);
+    strings.find('string[@name="app_name"]').text = name;
+    fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
+    events.emit('verbose', 'Wrote out Android application name to "' + name + '"');
+
+    // Java packages cannot support dashes
+    var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
+
+    var manifest = new AndroidManifest(locations.manifest);
+    var orig_pkg = manifest.getPackageId();
+
+    manifest.getActivity()
+        .setOrientation(findOrientationValue(platformConfig))
+        .setLaunchMode(findAndroidLaunchModePreference(platformConfig));
+
+    manifest.setVersionName(platformConfig.version())
+        .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
+        .setPackageId(pkg)
+        .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
+        .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
+        .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
+        .write();
+
+    var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
+    var java_files = shell.ls(javaPattern).filter(function(f) {
+        return shell.grep(/extends\s+CordovaActivity/g, f);
+    });
+
+    if (java_files.length === 0) {
+        throw new CordovaError('No Java files found which extend CordovaActivity.');
+    } else if(java_files.length > 1) {
+        events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
+    }
+
+    var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
+    shell.mkdir('-p', path.dirname(destFile));
+    shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
+    events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
+}
+
+
+// Consturct the default value for versionCode as
+// PATCH + MINOR * 100 + MAJOR * 10000
+// see http://developer.android.com/tools/publishing/versioning.html
+function default_versionCode(version) {
+    var nums = version.split('-')[0].split('.');
+    var versionCode = 0;
+    if (+nums[0]) {
+        versionCode += +nums[0] * 10000;
+    }
+    if (+nums[1]) {
+        versionCode += +nums[1] * 100;
+    }
+    if (+nums[2]) {
+        versionCode += +nums[2];
+    }
+    return versionCode;
+}
+
+function copyImage(src, resourcesDir, density, name) {
+    var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
+    var isNinePatch = !!/\.9\.png$/.exec(src);
+    var ninePatchName = name.replace(/\.png$/, '.9.png');
+
+    // default template does not have default asset for this density
+    if (!fs.existsSync(destFolder)) {
+        fs.mkdirSync(destFolder);
+    }
+
+    var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
+    events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
+    shell.cp('-f', src, destFilePath);
+}
+
+function handleSplashes(projectConfig, platformRoot) {
+    var resources = projectConfig.getSplashScreens('android');
+    // if there are "splash" elements in config.xml
+    if (resources.length > 0) {
+        deleteDefaultResourceAt(platformRoot, 'screen.png');
+        events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
+
+        // The source paths for icons and splashes are relative to
+        // project's config.xml location, so we use it as base path.
+        var projectRoot = path.dirname(projectConfig.path);
+        var destination = path.join(platformRoot, 'res');
+
+        var hadMdpi = false;
+        resources.forEach(function (resource) {
+            if (!resource.density) {
+                return;
+            }
+            if (resource.density == 'mdpi') {
+                hadMdpi = true;
+            }
+            copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
+        });
+        // There's no "default" drawable, so assume default == mdpi.
+        if (!hadMdpi && resources.defaultResource) {
+            copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
+        }
+    }
+}
+
+function handleIcons(projectConfig, platformRoot) {
+    var icons = projectConfig.getIcons('android');
+
+    // if there are icon elements in config.xml
+    if (icons.length === 0) {
+        events.emit('verbose', 'This app does not have launcher icons defined');
+        return;
+    }
+
+    deleteDefaultResourceAt(platformRoot, 'icon.png');
+
+    var android_icons = {};
+    var default_icon;
+    // http://developer.android.com/design/style/iconography.html
+    var sizeToDensityMap = {
+        36: 'ldpi',
+        48: 'mdpi',
+        72: 'hdpi',
+        96: 'xhdpi',
+        144: 'xxhdpi',
+        192: 'xxxhdpi'
+    };
+    // find the best matching icon for a given density or size
+    // @output android_icons
+    var parseIcon = function(icon, icon_size) {
+        // do I have a platform icon for that density already
+        var density = icon.density || sizeToDensityMap[icon_size];
+        if (!density) {
+            // invalid icon defition ( or unsupported size)
+            return;
+        }
+        var previous = android_icons[density];
+        if (previous && previous.platform) {
+            return;
+        }
+        android_icons[density] = icon;
+    };
+
+    // iterate over all icon elements to find the default icon and call parseIcon
+    for (var i=0; i<icons.length; i++) {
+        var icon = icons[i];
+        var size = icon.width;
+        if (!size) {
+            size = icon.height;
+        }
+        if (!size && !icon.density) {
+            if (default_icon) {
+                events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
+            } else {
+                default_icon = icon;
+            }
+        } else {
+            parseIcon(icon, size);
+        }
+    }
+
+    // The source paths for icons and splashes are relative to
+    // project's config.xml location, so we use it as base path.
+    var projectRoot = path.dirname(projectConfig.path);
+    var destination = path.join(platformRoot, 'res');
+    for (var density in android_icons) {
+        copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
+    }
+    // There's no "default" drawable, so assume default == mdpi.
+    if (default_icon && !android_icons.mdpi) {
+        copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
+    }
+}
+
+// remove the default resource name from all drawable folders
+function deleteDefaultResourceAt(baseDir, resourceName) {
+    shell.ls(path.join(baseDir, 'res/drawable-*'))
+    .forEach(function (drawableFolder) {
+        var imagePath = path.join(drawableFolder, resourceName);
+        shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
+        events.emit('verbose', 'Deleted ' + imagePath);
+    });
+}
+
+/**
+ * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
+ *   preference value and warns if it doesn't seems to be valid
+ *
+ * @param   {ConfigParser}  platformConfig  A configParser instance for
+ *   platform.
+ *
+ * @return  {String}                  Preference's value from config.xml or
+ *   default value, if there is no such preference. The default value is
+ *   'singleTop'
+ */
+function findAndroidLaunchModePreference(platformConfig) {
+    var launchMode = platformConfig.getPreference('AndroidLaunchMode');
+    if (!launchMode) {
+        // Return a default value
+        return 'singleTop';
+    }
+
+    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
+    var valid = expectedValues.indexOf(launchMode) >= 0;
+    if (!valid) {
+        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
+        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
+            launchMode + '. Expected values are: ' + expectedValues.join(', '));
+    }
+
+    return launchMode;
+}
+
+/**
+ * Queries ConfigParser object for the orientation <preference> value. Warns if
+ *   global preference value is not supported by platform.
+ *
+ * @param  {Object} platformConfig    ConfigParser object
+ *
+ * @return {String}           Global/platform-specific orientation in lower-case
+ *   (or empty string if both are undefined).
+ */
+function findOrientationValue(platformConfig) {
+
+    var ORIENTATION_DEFAULT = 'default';
+
+    var orientation = platformConfig.getPreference('orientation');
+    if (!orientation) {
+        return ORIENTATION_DEFAULT;
+    }
+
+    var GLOBAL_ORIENTATIONS = ['default', 'portrait','landscape'];
+    function isSupported(orientation) {
+        return GLOBAL_ORIENTATIONS.indexOf(orientation.toLowerCase()) >= 0;
+    }
+
+    // Check if the given global orientation is supported
+    if (orientation && isSupported(orientation)) {
+        return orientation;
+    }
+
+    events.emit('warn', 'Unsupported global orientation: ' + orientation +
+        '. Defaulting to value: ' + ORIENTATION_DEFAULT);
+    return ORIENTATION_DEFAULT;
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/update
----------------------------------------------------------------------
diff --git a/bin/update b/bin/update
index 4000df2..861c8d0 100755
--- a/bin/update
+++ b/bin/update
@@ -1,35 +1,35 @@
-#!/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 Api = require('./templates/cordova/Api');
-var args  = require('nopt')({
-    'link': Boolean,
-    'shared': Boolean,
-    'help': Boolean
-});
-
-if (args.help || args.argv.remain.length === 0) {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project> [--link]');
-    console.log('    --link will use the CordovaLib project directly instead of making a copy.');
-    process.exit(1);
-}
-
-Api.updatePlatform(args.argv.remain[0], {link: (args.link || args.shared)}).done();
+#!/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 Api = require('./templates/cordova/Api');
+var args  = require('nopt')({
+    'link': Boolean,
+    'shared': Boolean,
+    'help': Boolean
+});
+
+if (args.help || args.argv.remain.length === 0) {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project> [--link]');
+    console.log('    --link will use the CordovaLib project directly instead of making a copy.');
+    process.exit(1);
+}
+
+Api.updatePlatform(args.argv.remain[0], {link: (args.link || args.shared)}).done();

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index f49ca79..de7e9aa 100644
--- a/package.json
+++ b/package.json
@@ -1,46 +1,46 @@
-{
-    "name": "cordova-android",
-    "version": "5.0.0-dev",
-    "description": "cordova-android release",
-    "bin": {
-        "create": "bin/create"
-    },
-    "main": "bin/templates/cordova/Api.js",
-    "repository": {
-        "type": "git",
-        "url": "https://git-wip-us.apache.org/repos/asf/cordova-android.git"
-    },
-    "keywords": [
-        "android",
-        "cordova",
-        "apache"
-    ],
-    "scripts": {
-        "test": "npm run jshint && jasmine-node --color spec",
-        "test-build": "rm -rf \"test create\" && node ./bin/create \"test create\" com.test.app 応用 && \"./test create/cordova/build\" && rm -rf \"test create\"",
-        "jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint spec"
-    },
-    "author": "Apache Software Foundation",
-    "license": "Apache version 2.0",
-    "dependencies": {
-        "cordova-common": "^0.1.0",
-        "elementtree": "^0.1.6",
-        "nopt": "^3.0.1",
-        "properties-parser": "^0.3.0",
-        "q": "^1.4.1",
-        "shelljs": "^0.5.3"
-    },
-    "bundledDependencies": [
-        "cordova-common",
-        "elementtree",
-        "nopt",
-        "properties-parser",
-        "q",
-        "shelljs"
-    ],
-    "devDependencies": {
-        "jasmine-node": "^1.14.5",
-        "jshint": "^2.6.0",
-        "promise-matchers": "~0"
-    }
-}
+{
+    "name": "cordova-android",
+    "version": "5.0.0-dev",
+    "description": "cordova-android release",
+    "bin": {
+        "create": "bin/create"
+    },
+    "main": "bin/templates/cordova/Api.js",
+    "repository": {
+        "type": "git",
+        "url": "https://git-wip-us.apache.org/repos/asf/cordova-android.git"
+    },
+    "keywords": [
+        "android",
+        "cordova",
+        "apache"
+    ],
+    "scripts": {
+        "test": "npm run jshint && jasmine-node --color spec",
+        "test-build": "rm -rf \"test create\" && node ./bin/create \"test create\" com.test.app 応用 && \"./test create/cordova/build\" && rm -rf \"test create\"",
+        "jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint spec"
+    },
+    "author": "Apache Software Foundation",
+    "license": "Apache version 2.0",
+    "dependencies": {
+        "cordova-common": "^0.1.0",
+        "elementtree": "^0.1.6",
+        "nopt": "^3.0.1",
+        "properties-parser": "^0.3.0",
+        "q": "^1.4.1",
+        "shelljs": "^0.5.3"
+    },
+    "bundledDependencies": [
+        "cordova-common",
+        "elementtree",
+        "nopt",
+        "properties-parser",
+        "q",
+        "shelljs"
+    ],
+    "devDependencies": {
+        "jasmine-node": "^1.14.5",
+        "jshint": "^2.6.0",
+        "promise-matchers": "~0"
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[3/4] android commit: Fixed line endings

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/Api.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js
index 62899ef..7b7731f 100644
--- a/bin/templates/cordova/Api.js
+++ b/bin/templates/cordova/Api.js
@@ -1,492 +1,492 @@
-/**
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-
-var Q = require('q');
-var fs = require('fs');
-var path = require('path');
-var shell = require('shelljs');
-
-var CordovaError = require('cordova-common').CordovaError;
-var PlatformJson = require('cordova-common').PlatformJson;
-var ActionStack = require('cordova-common').ActionStack;
-var AndroidProject = require('./lib/AndroidProject');
-var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
-var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
-
-var ConsoleLogger = require('./lib/ConsoleLogger');
-var pluginHandlers = require('./lib/pluginHandlers');
-
-var PLATFORM = 'android';
-
-/**
- * Class, that acts as abstraction over particular platform. Encapsulates the
- *   platform's properties and methods.
- *
- * Platform that implements own PlatformApi instance _should implement all
- *   prototype methods_ of this class to be fully compatible with cordova-lib.
- *
- * The PlatformApi instance also should define the following field:
- *
- * * platform: String that defines a platform name.
- */
-function Api(platform, platformRootDir, events) {
-    this.platform = PLATFORM;
-    this.root = path.resolve(__dirname, '..');
-    this.events = events || ConsoleLogger.get();
-    // NOTE: trick to share one EventEmitter instance across all js code
-    require('cordova-common').events = this.events;
-
-    this._platformJson = PlatformJson.load(this.root, platform);
-    this._pluginInfoProvider = new PluginInfoProvider();
-    this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
-
-    var self = this;
-
-    this.locations = {
-        root: self.root,
-        www: path.join(self.root, 'assets/www'),
-        platformWww: path.join(self.root, 'platform_www'),
-        configXml: path.join(self.root, 'res/xml/config.xml'),
-        defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
-        strings: path.join(self.root, 'res/values/strings.xml'),
-        manifest: path.join(self.root, 'AndroidManifest.xml'),
-        // NOTE: Due to platformApi spec we need to return relative paths here
-        cordovaJs: 'bin/templates/project/assets/www/cordova.js',
-        cordovaJsSrc: 'cordova-js-src'
-    };
-}
-
-/**
- * Installs platform to specified directory and creates a platform project.
- *
- * @param  {String}  destination Destination directory, where insatll platform to
- * @param  {ConfigParser}  [config] ConfgiParser instance, used to retrieve
- *   project creation options, such as package id and project name.
- * @param  {Object}  [options]  An options object. The most common options are:
- * @param  {String}  [options.customTemplate]  A path to custom template, that
- *   should override the default one from platform.
- * @param  {Boolean}  [options.link]  Flag that indicates that platform's
- *   sources will be linked to installed platform instead of copying.
- * @param {EventEmitter} [events] An EventEmitter instance that will be used for
- *   logging purposes. If no EventEmitter provided, all events will be logged to
- *   console
- *
- * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
- *   instance or rejected with CordovaError.
- */
-Api.createPlatform = function (destination, config, options, events) {
-    return require('../../lib/create')
-    .create(destination, config, options, events || ConsoleLogger.get())
-    .then(function (destination) {
-        var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
-        return new PlatformApi(PLATFORM, destination, events);
-    });
-};
-
-/**
- * Updates already installed platform.
- *
- * @param  {String}  destination Destination directory, where platform installed
- * @param  {Object}  [options]  An options object. The most common options are:
- * @param  {String}  [options.customTemplate]  A path to custom template, that
- *   should override the default one from platform.
- * @param  {Boolean}  [options.link]  Flag that indicates that platform's
- *   sources will be linked to installed platform instead of copying.
- * @param {EventEmitter} [events] An EventEmitter instance that will be used for
- *   logging purposes. If no EventEmitter provided, all events will be logged to
- *   console
- *
- * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
- *   instance or rejected with CordovaError.
- */
-Api.updatePlatform = function (destination, options, events) {
-    return require('../../lib/create')
-    .update(destination, options, events || ConsoleLogger.get())
-    .then(function (destination) {
-        var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
-        return new PlatformApi('android', destination, events);
-    });
-};
-
-/**
- * Gets a CordovaPlatform object, that represents the platform structure.
- *
- * @return  {CordovaPlatform}  A structure that contains the description of
- *   platform's file structure and other properties of platform.
- */
-Api.prototype.getPlatformInfo = function () {
-    var result = {};
-    result.locations = this.locations;
-    result.root = this.root;
-    result.name = this.platform;
-    result.version = require('./version');
-    result.projectConfig = this._config;
-
-    return result;
-};
-
-/**
- * Updates installed platform with provided www assets and new app
- *   configuration. This method is required for CLI workflow and will be called
- *   each time before build, so the changes, made to app configuration and www
- *   code, will be applied to platform.
- *
- * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
- *   project structure and configuration, that should be applied to platform
- *   (contains project's www location and ConfigParser instance for project's
- *   config).
- *
- * @return  {Promise}  Return a promise either fulfilled, or rejected with
- *   CordovaError instance.
- */
-Api.prototype.prepare = function (cordovaProject) {
-    return require('./lib/prepare').prepare.call(this, cordovaProject);
-};
-
-/**
- * Installs a new plugin into platform. This method only copies non-www files
- *   (sources, libs, etc.) to platform. It also doesn't resolves the
- *   dependencies of plugin. Both of handling of www files, such as assets and
- *   js-files and resolving dependencies are the responsibility of caller.
- *
- * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
- *   that will be installed.
- * @param  {Object}  installOptions  An options object. Possible options below:
- * @param  {Boolean}  installOptions.link: Flag that specifies that plugin
- *   sources will be symlinked to app's directory instead of copying (if
- *   possible).
- * @param  {Object}  installOptions.variables  An object that represents
- *   variables that will be used to install plugin. See more details on plugin
- *   variables in documentation:
- *   https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
- *
- * @return  {Promise}  Return a promise either fulfilled, or rejected with
- *   CordovaError instance.
- */
-Api.prototype.addPlugin = function (plugin, installOptions) {
-
-    if (!plugin || plugin.constructor.name !== 'PluginInfo')
-        return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
-
-    installOptions = installOptions || {};
-    installOptions.variables = installOptions.variables || {};
-
-    var self = this;
-    var actions = new ActionStack();
-    var project = AndroidProject.getProjectFile(this.root);
-
-    // gather all files needs to be handled during install
-    plugin.getFilesAndFrameworks(this.platform)
-        .concat(plugin.getAssets(this.platform))
-        .concat(plugin.getJsModules(this.platform))
-    .forEach(function(item) {
-        actions.push(actions.createAction(
-            pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
-            pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
-    });
-
-    // run through the action stack
-    return actions.process(this.platform)
-    .then(function () {
-        if (project) {
-            project.write();
-        }
-
-        // Add PACKAGE_NAME variable into vars
-        if (!installOptions.variables.PACKAGE_NAME) {
-            installOptions.variables.PACKAGE_NAME = project.getPackageName();
-        }
-
-        self._munger
-            // Ignore passed `is_top_level` option since platform itself doesn't know
-            // anything about managing dependencies - it's responsibility of caller.
-            .add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
-            .save_all();
-
-        var targetDir = installOptions.usePlatformWww ?
-            self.locations.platformWww :
-            self.locations.www;
-
-        self._addModulesInfo(plugin, targetDir);
-    });
-};
-
-/**
- * Removes an installed plugin from platform.
- *
- * Since method accepts PluginInfo instance as input parameter instead of plugin
- *   id, caller shoud take care of managing/storing PluginInfo instances for
- *   future uninstalls.
- *
- * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
- *   that will be installed.
- *
- * @return  {Promise}  Return a promise either fulfilled, or rejected with
- *   CordovaError instance.
- */
-Api.prototype.removePlugin = function (plugin, uninstallOptions) {
-
-    if (!plugin || plugin.constructor.name !== 'PluginInfo')
-        return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
-
-    var self = this;
-    var actions = new ActionStack();
-    var project = AndroidProject.getProjectFile(this.root);
-
-    // queue up plugin files
-    plugin.getFilesAndFrameworks(this.platform)
-        .concat(plugin.getAssets(this.platform))
-        .concat(plugin.getJsModules(this.platform))
-    .forEach(function(item) {
-        actions.push(actions.createAction(
-            pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
-            pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
-    });
-
-    // run through the action stack
-    return actions.process(this.platform)
-    .then(function() {
-        if (project) {
-            project.write();
-        }
-
-        self._munger
-            // Ignore passed `is_top_level` option since platform itself doesn't know
-            // anything about managing dependencies - it's responsibility of caller.
-            .remove_plugin_changes(plugin, /*is_top_level=*/true)
-            .save_all();
-
-        var targetDir = uninstallOptions.usePlatformWww ?
-            self.locations.platformWww :
-            self.locations.www;
-
-        self._removeModulesInfo(plugin, targetDir);
-    });
-};
-
-/**
- * Builds an application package for current platform.
- *
- * @param  {Object}  buildOptions  A build options. This object's structure is
- *   highly depends on platform's specific. The most common options are:
- * @param  {Boolean}  buildOptions.debug  Indicates that packages should be
- *   built with debug configuration. This is set to true by default unless the
- *   'release' option is not specified.
- * @param  {Boolean}  buildOptions.release  Indicates that packages should be
- *   built with release configuration. If not set to true, debug configuration
- *   will be used.
- * @param   {Boolean}  buildOptions.device  Specifies that built app is intended
- *   to run on device
- * @param   {Boolean}  buildOptions.emulator: Specifies that built app is
- *   intended to run on emulator
- * @param   {String}  buildOptions.target  Specifies the device id that will be
- *   used to run built application.
- * @param   {Boolean}  buildOptions.nobuild  Indicates that this should be a
- *   dry-run call, so no build artifacts will be produced.
- * @param   {String[]}  buildOptions.archs  Specifies chip architectures which
- *   app packages should be built for. List of valid architectures is depends on
- *   platform.
- * @param   {String}  buildOptions.buildConfig  The path to build configuration
- *   file. The format of this file is depends on platform.
- * @param   {String[]} buildOptions.argv Raw array of command-line arguments,
- *   passed to `build` command. The purpose of this property is to pass a
- *   platform-specific arguments, and eventually let platform define own
- *   arguments processing logic.
- *
- * @return {Promise<Object[]>} A promise either fulfilled with an array of build
- *   artifacts (application packages) if package was built successfully,
- *   or rejected with CordovaError. The resultant build artifact objects is not
- *   strictly typed and may conatin arbitrary set of fields as in sample below.
- *
- *     {
- *         architecture: 'x86',
- *         buildType: 'debug',
- *         path: '/path/to/build',
- *         type: 'app'
- *     }
- *
- * The return value in most cases will contain only one item but in some cases
- *   there could be multiple items in output array, e.g. when multiple
- *   arhcitectures is specified.
- */
-Api.prototype.build = function (buildOptions) {
-    var self = this;
-    return require('./lib/check_reqs').run()
-    .then(function () {
-        return require('./lib/build').run.call(self, buildOptions);
-    })
-    .then(function (buildResults) {
-        // Cast build result to array of build artifacts
-        return buildResults.apkPaths.map(function (apkPath) {
-            return {
-                buildType: buildResults.buildType,
-                buildMethod: buildResults.buildMethod,
-                path: apkPath,
-                type: 'apk'
-            };
-        });
-    });
-};
-
-/**
- * Builds an application package for current platform and runs it on
- *   specified/default device. If no 'device'/'emulator'/'target' options are
- *   specified, then tries to run app on default device if connected, otherwise
- *   runs the app on emulator.
- *
- * @param   {Object}  runOptions  An options object. The structure is the same
- *   as for build options.
- *
- * @return {Promise} A promise either fulfilled if package was built and ran
- *   successfully, or rejected with CordovaError.
- */
-Api.prototype.run = function(runOptions) {
-    var self = this;
-    return require('./lib/check_reqs').run()
-    .then(function () {
-        return require('./lib/run').run.call(self, runOptions);
-    });
-};
-
-/**
- * Cleans out the build artifacts from platform's directory.
- *
- * @return  {Promise}  Return a promise either fulfilled, or rejected with
- *   CordovaError.
- */
-Api.prototype.clean = function(cleanOptions) {
-    var self = this;
-    return require('./lib/check_reqs').run()
-    .then(function () {
-        return require('./lib/build').runClean.call(self, cleanOptions);
-    });
-};
-
-/**
- * Performs a requirements check for current platform. Each platform defines its
- *   own set of requirements, which should be resolved before platform can be
- *   built successfully.
- *
- * @return  {Promise<Requirement[]>}  Promise, resolved with set of Requirement
- *   objects for current platform.
- */
-Api.prototype.requirements = function() {
-    return require('./lib/check_reqs').check_all();
-};
-
-module.exports = Api;
-
-/**
- * Removes the specified modules from list of installed modules and updates
- *   platform_json and cordova_plugins.js on disk.
- *
- * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
- *   needs to be added.
- * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
- *   should be written to.
- */
-Api.prototype._addModulesInfo = function(plugin, targetDir) {
-    var installedModules = this._platformJson.root.modules || [];
-
-    var installedPaths = installedModules.map(function (installedModule) {
-        return installedModule.file;
-    });
-
-    var modulesToInstall = plugin.getJsModules(this.platform)
-    .filter(function (moduleToInstall) {
-        return installedPaths.indexOf(moduleToInstall.file) === -1;
-    }).map(function (moduleToInstall) {
-        var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
-        var obj = {
-            file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
-            id: moduleName
-        };
-        if (moduleToInstall.clobbers.length > 0) {
-            obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
-        }
-        if (moduleToInstall.merges.length > 0) {
-            obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
-        }
-        if (moduleToInstall.runs) {
-            obj.runs = true;
-        }
-
-        return obj;
-    });
-
-    this._platformJson.root.modules = installedModules.concat(modulesToInstall);
-    this._writePluginModules(targetDir);
-    this._platformJson.save();
-};
-
-/**
- * Removes the specified modules from list of installed modules and updates
- *   platform_json and cordova_plugins.js on disk.
- *
- * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
- *   needs to be removed.
- * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
- *   should be written to.
- */
-Api.prototype._removeModulesInfo = function(plugin, targetDir) {
-    var installedModules = this._platformJson.root.modules || [];
-    var modulesToRemove = plugin.getJsModules(this.platform)
-    .map(function (jsModule) {
-        return  ['plugins', plugin.id, jsModule.src].join('/');
-    });
-
-    var updatedModules = installedModules
-    .filter(function (installedModule) {
-        return (modulesToRemove.indexOf(installedModule.file) === -1);
-    });
-
-    this._platformJson.root.modules = updatedModules;
-    this._writePluginModules(targetDir);
-    this._platformJson.save();
-};
-
-/**
- * Fetches all installed modules, generates cordova_plugins contents and writes
- *   it to file.
- *
- * @param   {String}  targetDir  Directory, where write cordova_plugins.js to.
- *   Ususally it is either <platform>/www or <platform>/platform_www
- *   directories.
- */
-Api.prototype._writePluginModules = function (targetDir) {
-    var self = this;
-    // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
-    var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
-    final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, '    ') + ';\n';
-    final_contents += 'module.exports.metadata = \n';
-    final_contents += '// TOP OF METADATA\n';
-
-    var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
-    .reduce(function (metadata, plugin) {
-        metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
-        return metadata;
-    }, {});
-
-    final_contents += JSON.stringify(pluginMetadata, null, 4) + '\n';
-    final_contents += '// BOTTOM OF METADATA\n';
-    final_contents += '});'; // Close cordova.define.
-
-    shell.mkdir('-p', targetDir);
-    fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
-};
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+
+var CordovaError = require('cordova-common').CordovaError;
+var PlatformJson = require('cordova-common').PlatformJson;
+var ActionStack = require('cordova-common').ActionStack;
+var AndroidProject = require('./lib/AndroidProject');
+var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
+var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
+
+var ConsoleLogger = require('./lib/ConsoleLogger');
+var pluginHandlers = require('./lib/pluginHandlers');
+
+var PLATFORM = 'android';
+
+/**
+ * Class, that acts as abstraction over particular platform. Encapsulates the
+ *   platform's properties and methods.
+ *
+ * Platform that implements own PlatformApi instance _should implement all
+ *   prototype methods_ of this class to be fully compatible with cordova-lib.
+ *
+ * The PlatformApi instance also should define the following field:
+ *
+ * * platform: String that defines a platform name.
+ */
+function Api(platform, platformRootDir, events) {
+    this.platform = PLATFORM;
+    this.root = path.resolve(__dirname, '..');
+    this.events = events || ConsoleLogger.get();
+    // NOTE: trick to share one EventEmitter instance across all js code
+    require('cordova-common').events = this.events;
+
+    this._platformJson = PlatformJson.load(this.root, platform);
+    this._pluginInfoProvider = new PluginInfoProvider();
+    this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
+
+    var self = this;
+
+    this.locations = {
+        root: self.root,
+        www: path.join(self.root, 'assets/www'),
+        platformWww: path.join(self.root, 'platform_www'),
+        configXml: path.join(self.root, 'res/xml/config.xml'),
+        defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
+        strings: path.join(self.root, 'res/values/strings.xml'),
+        manifest: path.join(self.root, 'AndroidManifest.xml'),
+        // NOTE: Due to platformApi spec we need to return relative paths here
+        cordovaJs: 'bin/templates/project/assets/www/cordova.js',
+        cordovaJsSrc: 'cordova-js-src'
+    };
+}
+
+/**
+ * Installs platform to specified directory and creates a platform project.
+ *
+ * @param  {String}  destination Destination directory, where insatll platform to
+ * @param  {ConfigParser}  [config] ConfgiParser instance, used to retrieve
+ *   project creation options, such as package id and project name.
+ * @param  {Object}  [options]  An options object. The most common options are:
+ * @param  {String}  [options.customTemplate]  A path to custom template, that
+ *   should override the default one from platform.
+ * @param  {Boolean}  [options.link]  Flag that indicates that platform's
+ *   sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ *   logging purposes. If no EventEmitter provided, all events will be logged to
+ *   console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ *   instance or rejected with CordovaError.
+ */
+Api.createPlatform = function (destination, config, options, events) {
+    return require('../../lib/create')
+    .create(destination, config, options, events || ConsoleLogger.get())
+    .then(function (destination) {
+        var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+        return new PlatformApi(PLATFORM, destination, events);
+    });
+};
+
+/**
+ * Updates already installed platform.
+ *
+ * @param  {String}  destination Destination directory, where platform installed
+ * @param  {Object}  [options]  An options object. The most common options are:
+ * @param  {String}  [options.customTemplate]  A path to custom template, that
+ *   should override the default one from platform.
+ * @param  {Boolean}  [options.link]  Flag that indicates that platform's
+ *   sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ *   logging purposes. If no EventEmitter provided, all events will be logged to
+ *   console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ *   instance or rejected with CordovaError.
+ */
+Api.updatePlatform = function (destination, options, events) {
+    return require('../../lib/create')
+    .update(destination, options, events || ConsoleLogger.get())
+    .then(function (destination) {
+        var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+        return new PlatformApi('android', destination, events);
+    });
+};
+
+/**
+ * Gets a CordovaPlatform object, that represents the platform structure.
+ *
+ * @return  {CordovaPlatform}  A structure that contains the description of
+ *   platform's file structure and other properties of platform.
+ */
+Api.prototype.getPlatformInfo = function () {
+    var result = {};
+    result.locations = this.locations;
+    result.root = this.root;
+    result.name = this.platform;
+    result.version = require('./version');
+    result.projectConfig = this._config;
+
+    return result;
+};
+
+/**
+ * Updates installed platform with provided www assets and new app
+ *   configuration. This method is required for CLI workflow and will be called
+ *   each time before build, so the changes, made to app configuration and www
+ *   code, will be applied to platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ *   project structure and configuration, that should be applied to platform
+ *   (contains project's www location and ConfigParser instance for project's
+ *   config).
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.prepare = function (cordovaProject) {
+    return require('./lib/prepare').prepare.call(this, cordovaProject);
+};
+
+/**
+ * Installs a new plugin into platform. This method only copies non-www files
+ *   (sources, libs, etc.) to platform. It also doesn't resolves the
+ *   dependencies of plugin. Both of handling of www files, such as assets and
+ *   js-files and resolving dependencies are the responsibility of caller.
+ *
+ * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
+ *   that will be installed.
+ * @param  {Object}  installOptions  An options object. Possible options below:
+ * @param  {Boolean}  installOptions.link: Flag that specifies that plugin
+ *   sources will be symlinked to app's directory instead of copying (if
+ *   possible).
+ * @param  {Object}  installOptions.variables  An object that represents
+ *   variables that will be used to install plugin. See more details on plugin
+ *   variables in documentation:
+ *   https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.addPlugin = function (plugin, installOptions) {
+
+    if (!plugin || plugin.constructor.name !== 'PluginInfo')
+        return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
+
+    installOptions = installOptions || {};
+    installOptions.variables = installOptions.variables || {};
+
+    var self = this;
+    var actions = new ActionStack();
+    var project = AndroidProject.getProjectFile(this.root);
+
+    // gather all files needs to be handled during install
+    plugin.getFilesAndFrameworks(this.platform)
+        .concat(plugin.getAssets(this.platform))
+        .concat(plugin.getJsModules(this.platform))
+    .forEach(function(item) {
+        actions.push(actions.createAction(
+            pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
+            pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
+    });
+
+    // run through the action stack
+    return actions.process(this.platform)
+    .then(function () {
+        if (project) {
+            project.write();
+        }
+
+        // Add PACKAGE_NAME variable into vars
+        if (!installOptions.variables.PACKAGE_NAME) {
+            installOptions.variables.PACKAGE_NAME = project.getPackageName();
+        }
+
+        self._munger
+            // Ignore passed `is_top_level` option since platform itself doesn't know
+            // anything about managing dependencies - it's responsibility of caller.
+            .add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
+            .save_all();
+
+        var targetDir = installOptions.usePlatformWww ?
+            self.locations.platformWww :
+            self.locations.www;
+
+        self._addModulesInfo(plugin, targetDir);
+    });
+};
+
+/**
+ * Removes an installed plugin from platform.
+ *
+ * Since method accepts PluginInfo instance as input parameter instead of plugin
+ *   id, caller shoud take care of managing/storing PluginInfo instances for
+ *   future uninstalls.
+ *
+ * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin
+ *   that will be installed.
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError instance.
+ */
+Api.prototype.removePlugin = function (plugin, uninstallOptions) {
+
+    if (!plugin || plugin.constructor.name !== 'PluginInfo')
+        return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
+
+    var self = this;
+    var actions = new ActionStack();
+    var project = AndroidProject.getProjectFile(this.root);
+
+    // queue up plugin files
+    plugin.getFilesAndFrameworks(this.platform)
+        .concat(plugin.getAssets(this.platform))
+        .concat(plugin.getJsModules(this.platform))
+    .forEach(function(item) {
+        actions.push(actions.createAction(
+            pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
+            pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
+    });
+
+    // run through the action stack
+    return actions.process(this.platform)
+    .then(function() {
+        if (project) {
+            project.write();
+        }
+
+        self._munger
+            // Ignore passed `is_top_level` option since platform itself doesn't know
+            // anything about managing dependencies - it's responsibility of caller.
+            .remove_plugin_changes(plugin, /*is_top_level=*/true)
+            .save_all();
+
+        var targetDir = uninstallOptions.usePlatformWww ?
+            self.locations.platformWww :
+            self.locations.www;
+
+        self._removeModulesInfo(plugin, targetDir);
+    });
+};
+
+/**
+ * Builds an application package for current platform.
+ *
+ * @param  {Object}  buildOptions  A build options. This object's structure is
+ *   highly depends on platform's specific. The most common options are:
+ * @param  {Boolean}  buildOptions.debug  Indicates that packages should be
+ *   built with debug configuration. This is set to true by default unless the
+ *   'release' option is not specified.
+ * @param  {Boolean}  buildOptions.release  Indicates that packages should be
+ *   built with release configuration. If not set to true, debug configuration
+ *   will be used.
+ * @param   {Boolean}  buildOptions.device  Specifies that built app is intended
+ *   to run on device
+ * @param   {Boolean}  buildOptions.emulator: Specifies that built app is
+ *   intended to run on emulator
+ * @param   {String}  buildOptions.target  Specifies the device id that will be
+ *   used to run built application.
+ * @param   {Boolean}  buildOptions.nobuild  Indicates that this should be a
+ *   dry-run call, so no build artifacts will be produced.
+ * @param   {String[]}  buildOptions.archs  Specifies chip architectures which
+ *   app packages should be built for. List of valid architectures is depends on
+ *   platform.
+ * @param   {String}  buildOptions.buildConfig  The path to build configuration
+ *   file. The format of this file is depends on platform.
+ * @param   {String[]} buildOptions.argv Raw array of command-line arguments,
+ *   passed to `build` command. The purpose of this property is to pass a
+ *   platform-specific arguments, and eventually let platform define own
+ *   arguments processing logic.
+ *
+ * @return {Promise<Object[]>} A promise either fulfilled with an array of build
+ *   artifacts (application packages) if package was built successfully,
+ *   or rejected with CordovaError. The resultant build artifact objects is not
+ *   strictly typed and may conatin arbitrary set of fields as in sample below.
+ *
+ *     {
+ *         architecture: 'x86',
+ *         buildType: 'debug',
+ *         path: '/path/to/build',
+ *         type: 'app'
+ *     }
+ *
+ * The return value in most cases will contain only one item but in some cases
+ *   there could be multiple items in output array, e.g. when multiple
+ *   arhcitectures is specified.
+ */
+Api.prototype.build = function (buildOptions) {
+    var self = this;
+    return require('./lib/check_reqs').run()
+    .then(function () {
+        return require('./lib/build').run.call(self, buildOptions);
+    })
+    .then(function (buildResults) {
+        // Cast build result to array of build artifacts
+        return buildResults.apkPaths.map(function (apkPath) {
+            return {
+                buildType: buildResults.buildType,
+                buildMethod: buildResults.buildMethod,
+                path: apkPath,
+                type: 'apk'
+            };
+        });
+    });
+};
+
+/**
+ * Builds an application package for current platform and runs it on
+ *   specified/default device. If no 'device'/'emulator'/'target' options are
+ *   specified, then tries to run app on default device if connected, otherwise
+ *   runs the app on emulator.
+ *
+ * @param   {Object}  runOptions  An options object. The structure is the same
+ *   as for build options.
+ *
+ * @return {Promise} A promise either fulfilled if package was built and ran
+ *   successfully, or rejected with CordovaError.
+ */
+Api.prototype.run = function(runOptions) {
+    var self = this;
+    return require('./lib/check_reqs').run()
+    .then(function () {
+        return require('./lib/run').run.call(self, runOptions);
+    });
+};
+
+/**
+ * Cleans out the build artifacts from platform's directory.
+ *
+ * @return  {Promise}  Return a promise either fulfilled, or rejected with
+ *   CordovaError.
+ */
+Api.prototype.clean = function(cleanOptions) {
+    var self = this;
+    return require('./lib/check_reqs').run()
+    .then(function () {
+        return require('./lib/build').runClean.call(self, cleanOptions);
+    });
+};
+
+/**
+ * Performs a requirements check for current platform. Each platform defines its
+ *   own set of requirements, which should be resolved before platform can be
+ *   built successfully.
+ *
+ * @return  {Promise<Requirement[]>}  Promise, resolved with set of Requirement
+ *   objects for current platform.
+ */
+Api.prototype.requirements = function() {
+    return require('./lib/check_reqs').check_all();
+};
+
+module.exports = Api;
+
+/**
+ * Removes the specified modules from list of installed modules and updates
+ *   platform_json and cordova_plugins.js on disk.
+ *
+ * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
+ *   needs to be added.
+ * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
+ *   should be written to.
+ */
+Api.prototype._addModulesInfo = function(plugin, targetDir) {
+    var installedModules = this._platformJson.root.modules || [];
+
+    var installedPaths = installedModules.map(function (installedModule) {
+        return installedModule.file;
+    });
+
+    var modulesToInstall = plugin.getJsModules(this.platform)
+    .filter(function (moduleToInstall) {
+        return installedPaths.indexOf(moduleToInstall.file) === -1;
+    }).map(function (moduleToInstall) {
+        var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
+        var obj = {
+            file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
+            id: moduleName
+        };
+        if (moduleToInstall.clobbers.length > 0) {
+            obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
+        }
+        if (moduleToInstall.merges.length > 0) {
+            obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
+        }
+        if (moduleToInstall.runs) {
+            obj.runs = true;
+        }
+
+        return obj;
+    });
+
+    this._platformJson.root.modules = installedModules.concat(modulesToInstall);
+    this._writePluginModules(targetDir);
+    this._platformJson.save();
+};
+
+/**
+ * Removes the specified modules from list of installed modules and updates
+ *   platform_json and cordova_plugins.js on disk.
+ *
+ * @param   {PluginInfo}  plugin  PluginInfo instance for plugin, which modules
+ *   needs to be removed.
+ * @param   {String}  targetDir  The directory, where updated cordova_plugins.js
+ *   should be written to.
+ */
+Api.prototype._removeModulesInfo = function(plugin, targetDir) {
+    var installedModules = this._platformJson.root.modules || [];
+    var modulesToRemove = plugin.getJsModules(this.platform)
+    .map(function (jsModule) {
+        return  ['plugins', plugin.id, jsModule.src].join('/');
+    });
+
+    var updatedModules = installedModules
+    .filter(function (installedModule) {
+        return (modulesToRemove.indexOf(installedModule.file) === -1);
+    });
+
+    this._platformJson.root.modules = updatedModules;
+    this._writePluginModules(targetDir);
+    this._platformJson.save();
+};
+
+/**
+ * Fetches all installed modules, generates cordova_plugins contents and writes
+ *   it to file.
+ *
+ * @param   {String}  targetDir  Directory, where write cordova_plugins.js to.
+ *   Ususally it is either <platform>/www or <platform>/platform_www
+ *   directories.
+ */
+Api.prototype._writePluginModules = function (targetDir) {
+    var self = this;
+    // Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
+    var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
+    final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, '    ') + ';\n';
+    final_contents += 'module.exports.metadata = \n';
+    final_contents += '// TOP OF METADATA\n';
+
+    var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
+    .reduce(function (metadata, plugin) {
+        metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
+        return metadata;
+    }, {});
+
+    final_contents += JSON.stringify(pluginMetadata, null, 4) + '\n';
+    final_contents += '// BOTTOM OF METADATA\n';
+    final_contents += '});'; // Close cordova.define.
+
+    shell.mkdir('-p', targetDir);
+    fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
+};

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/Adb.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/Adb.js b/bin/templates/cordova/lib/Adb.js
index e4fc363..fc97f66 100644
--- a/bin/templates/cordova/lib/Adb.js
+++ b/bin/templates/cordova/lib/Adb.js
@@ -1,78 +1,78 @@
-
-var Q = require('q');
-var os = require('os');
-var events = require('cordova-common').events;
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-
-var Adb = {};
-
-function isDevice(line) {
-    return line.match(/\w+\tdevice/) && !line.match(/emulator/);
-}
-
-function isEmulator(line) {
-    return line.match(/device/) && line.match(/emulator/);
-}
-
-/**
- * Lists available/connected devices and emulators
- *
- * @param   {Object}   opts            Various options
- * @param   {Boolean}  opts.emulators  Specifies whether this method returns
- *   emulators only
- *
- * @return  {Promise<String[]>}        list of available/connected
- *   devices/emulators
- */
-Adb.devices = function (opts) {
-    return spawn('adb', ['devices'], {cwd: os.tmpdir()})
-    .then(function(output) {
-        return output.split('\n').filter(function (line) {
-            // Filter out either real devices or emulators, depending on options
-            return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
-        }).map(function (line) {
-            return line.replace(/\tdevice/, '').replace('\r', '');
-        });
-    });
-};
-
-Adb.install = function (target, packagePath, opts) {
-    events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
-    var args = ['-s', target, 'install'];
-    if (opts && opts.replace) args.push('-r');
-    return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
-    .then(function(output) {
-        // 'adb install' seems to always returns no error, even if installation fails
-        // so we catching output to detect installation failure
-        if (output.match(/Failure/))
-            return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
-    });
-};
-
-Adb.uninstall = function (target, packageId) {
-    events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
-    return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
-};
-
-Adb.shell = function (target, shellCommand) {
-    events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
-    var args = ['-s', target, 'shell'];
-    shellCommand = shellCommand.split(/\s+/);
-    return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
-    .catch(function (output) {
-        return Q.reject(new CordovaError('Failed to execute shell command "' +
-            shellCommand + '"" on device: ' + output));
-    });
-};
-
-Adb.start = function (target, activityName) {
-    events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
-    return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
-    .catch(function (output) {
-        return Q.reject(new CordovaError('Failed to start application "' +
-            activityName + '"" on device: ' + output));
-    });
-};
-
-module.exports = Adb;
+
+var Q = require('q');
+var os = require('os');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+var Adb = {};
+
+function isDevice(line) {
+    return line.match(/\w+\tdevice/) && !line.match(/emulator/);
+}
+
+function isEmulator(line) {
+    return line.match(/device/) && line.match(/emulator/);
+}
+
+/**
+ * Lists available/connected devices and emulators
+ *
+ * @param   {Object}   opts            Various options
+ * @param   {Boolean}  opts.emulators  Specifies whether this method returns
+ *   emulators only
+ *
+ * @return  {Promise<String[]>}        list of available/connected
+ *   devices/emulators
+ */
+Adb.devices = function (opts) {
+    return spawn('adb', ['devices'], {cwd: os.tmpdir()})
+    .then(function(output) {
+        return output.split('\n').filter(function (line) {
+            // Filter out either real devices or emulators, depending on options
+            return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
+        }).map(function (line) {
+            return line.replace(/\tdevice/, '').replace('\r', '');
+        });
+    });
+};
+
+Adb.install = function (target, packagePath, opts) {
+    events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
+    var args = ['-s', target, 'install'];
+    if (opts && opts.replace) args.push('-r');
+    return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
+    .then(function(output) {
+        // 'adb install' seems to always returns no error, even if installation fails
+        // so we catching output to detect installation failure
+        if (output.match(/Failure/))
+            return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
+    });
+};
+
+Adb.uninstall = function (target, packageId) {
+    events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
+    return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
+};
+
+Adb.shell = function (target, shellCommand) {
+    events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
+    var args = ['-s', target, 'shell'];
+    shellCommand = shellCommand.split(/\s+/);
+    return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
+    .catch(function (output) {
+        return Q.reject(new CordovaError('Failed to execute shell command "' +
+            shellCommand + '"" on device: ' + output));
+    });
+};
+
+Adb.start = function (target, activityName) {
+    events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
+    return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
+    .catch(function (output) {
+        return Q.reject(new CordovaError('Failed to start application "' +
+            activityName + '"" on device: ' + output));
+    });
+};
+
+module.exports = Adb;

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/AndroidManifest.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/AndroidManifest.js b/bin/templates/cordova/lib/AndroidManifest.js
index 770d527..3654ada 100644
--- a/bin/templates/cordova/lib/AndroidManifest.js
+++ b/bin/templates/cordova/lib/AndroidManifest.js
@@ -1,161 +1,161 @@
-/**
-    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 fs = require('fs');
-var et = require('elementtree');
-var xml= require('cordova-common').xmlHelpers;
-
-var DEFAULT_ORIENTATION = 'default';
-
-/** Wraps an AndroidManifest file */
-function AndroidManifest(path) {
-    this.path = path;
-    this.doc = xml.parseElementtreeSync(path);
-    if (this.doc.getroot().tag !== 'manifest') {
-        throw new Error(path + ' has incorrect root node name (expected "manifest")');
-    }
-}
-
-AndroidManifest.prototype.getVersionName = function() {
-    return this.doc.getroot().attrib['android:versionName'];
-};
-
-AndroidManifest.prototype.setVersionName = function(versionName) {
-    this.doc.getroot().attrib['android:versionName'] = versionName;
-    return this;
-};
-
-AndroidManifest.prototype.getVersionCode = function() {
-    return this.doc.getroot().attrib['android:versionCode'];
-};
-
-AndroidManifest.prototype.setVersionCode = function(versionCode) {
-    this.doc.getroot().attrib['android:versionCode'] = versionCode;
-    return this;
-};
-
-AndroidManifest.prototype.getPackageId = function() {
-    /*jshint -W069 */
-    return this.doc.getroot().attrib['package'];
-    /*jshint +W069 */
-};
-
-AndroidManifest.prototype.setPackageId = function(pkgId) {
-    /*jshint -W069 */
-    this.doc.getroot().attrib['package'] = pkgId;
-    /*jshint +W069 */
-    return this;
-};
-
-AndroidManifest.prototype.getActivity = function() {
-    var activity = this.doc.getroot().find('./application/activity');
-    return {
-        getName: function () {
-            return activity.attrib['android:name'];
-        },
-        setName: function (name) {
-            if (!name) {
-                delete activity.attrib['android:name'];
-            } else {
-                activity.attrib['android:name'] = name;
-            }
-            return this;
-        },
-        getOrientation: function () {
-            return activity.attrib['android:screenOrientation'];
-        },
-        setOrientation: function (orientation) {
-            if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
-                delete activity.attrib['android:screenOrientation'];
-            } else {
-                activity.attrib['android:screenOrientation'] = orientation;
-            }
-            return this;
-        },
-        getLaunchMode: function () {
-            return activity.attrib['android:launchMode'];
-        },
-        setLaunchMode: function (launchMode) {
-            if (!launchMode) {
-                delete activity.attrib['android:launchMode'];
-            } else {
-                activity.attrib['android:launchMode'] = launchMode;
-            }
-            return this;
-        }
-    };
-};
-
-['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
-.forEach(function(sdkPrefName) {
-    // Copy variable reference to avoid closure issues
-    var prefName = sdkPrefName;
-
-    AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
-        var usesSdk = this.doc.getroot().find('./uses-sdk');
-        return usesSdk && usesSdk.attrib['android:' + prefName];
-    };
-
-    AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
-        var usesSdk = this.doc.getroot().find('./uses-sdk');
-
-        if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
-            usesSdk = new et.Element('uses-sdk');
-            this.doc.getroot().append(usesSdk);
-        }
-
-        if (prefValue) {
-            usesSdk.attrib['android:' + prefName] = prefValue;
-        }
-
-        return this;
-    };
-});
-
-AndroidManifest.prototype.getDebuggable = function() {
-    return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
-};
-
-AndroidManifest.prototype.setDebuggable = function(value) {
-    var application = this.doc.getroot().find('./application');
-    if (value) {
-        application.attrib['android:debuggable'] = 'true';
-    } else {
-        // The default value is "false", so we can remove attribute at all.
-        delete application.attrib['android:debuggable'];
-    }
-    return this;
-};
-
-/**
- * Writes manifest to disk syncronously. If filename is specified, then manifest
- *   will be written to that file
- *
- * @param   {String}  [destPath]  File to write manifest to. If omitted,
- *   manifest will be written to file it has been read from.
- */
-AndroidManifest.prototype.write = function(destPath) {
-    fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
-};
-
-module.exports = AndroidManifest;
-
-function capitalize (str) {
-    return str.charAt(0).toUpperCase() + str.slice(1);
-}
+/**
+    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 fs = require('fs');
+var et = require('elementtree');
+var xml= require('cordova-common').xmlHelpers;
+
+var DEFAULT_ORIENTATION = 'default';
+
+/** Wraps an AndroidManifest file */
+function AndroidManifest(path) {
+    this.path = path;
+    this.doc = xml.parseElementtreeSync(path);
+    if (this.doc.getroot().tag !== 'manifest') {
+        throw new Error(path + ' has incorrect root node name (expected "manifest")');
+    }
+}
+
+AndroidManifest.prototype.getVersionName = function() {
+    return this.doc.getroot().attrib['android:versionName'];
+};
+
+AndroidManifest.prototype.setVersionName = function(versionName) {
+    this.doc.getroot().attrib['android:versionName'] = versionName;
+    return this;
+};
+
+AndroidManifest.prototype.getVersionCode = function() {
+    return this.doc.getroot().attrib['android:versionCode'];
+};
+
+AndroidManifest.prototype.setVersionCode = function(versionCode) {
+    this.doc.getroot().attrib['android:versionCode'] = versionCode;
+    return this;
+};
+
+AndroidManifest.prototype.getPackageId = function() {
+    /*jshint -W069 */
+    return this.doc.getroot().attrib['package'];
+    /*jshint +W069 */
+};
+
+AndroidManifest.prototype.setPackageId = function(pkgId) {
+    /*jshint -W069 */
+    this.doc.getroot().attrib['package'] = pkgId;
+    /*jshint +W069 */
+    return this;
+};
+
+AndroidManifest.prototype.getActivity = function() {
+    var activity = this.doc.getroot().find('./application/activity');
+    return {
+        getName: function () {
+            return activity.attrib['android:name'];
+        },
+        setName: function (name) {
+            if (!name) {
+                delete activity.attrib['android:name'];
+            } else {
+                activity.attrib['android:name'] = name;
+            }
+            return this;
+        },
+        getOrientation: function () {
+            return activity.attrib['android:screenOrientation'];
+        },
+        setOrientation: function (orientation) {
+            if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
+                delete activity.attrib['android:screenOrientation'];
+            } else {
+                activity.attrib['android:screenOrientation'] = orientation;
+            }
+            return this;
+        },
+        getLaunchMode: function () {
+            return activity.attrib['android:launchMode'];
+        },
+        setLaunchMode: function (launchMode) {
+            if (!launchMode) {
+                delete activity.attrib['android:launchMode'];
+            } else {
+                activity.attrib['android:launchMode'] = launchMode;
+            }
+            return this;
+        }
+    };
+};
+
+['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
+.forEach(function(sdkPrefName) {
+    // Copy variable reference to avoid closure issues
+    var prefName = sdkPrefName;
+
+    AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
+        var usesSdk = this.doc.getroot().find('./uses-sdk');
+        return usesSdk && usesSdk.attrib['android:' + prefName];
+    };
+
+    AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
+        var usesSdk = this.doc.getroot().find('./uses-sdk');
+
+        if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
+            usesSdk = new et.Element('uses-sdk');
+            this.doc.getroot().append(usesSdk);
+        }
+
+        if (prefValue) {
+            usesSdk.attrib['android:' + prefName] = prefValue;
+        }
+
+        return this;
+    };
+});
+
+AndroidManifest.prototype.getDebuggable = function() {
+    return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
+};
+
+AndroidManifest.prototype.setDebuggable = function(value) {
+    var application = this.doc.getroot().find('./application');
+    if (value) {
+        application.attrib['android:debuggable'] = 'true';
+    } else {
+        // The default value is "false", so we can remove attribute at all.
+        delete application.attrib['android:debuggable'];
+    }
+    return this;
+};
+
+/**
+ * Writes manifest to disk syncronously. If filename is specified, then manifest
+ *   will be written to that file
+ *
+ * @param   {String}  [destPath]  File to write manifest to. If omitted,
+ *   manifest will be written to file it has been read from.
+ */
+AndroidManifest.prototype.write = function(destPath) {
+    fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
+};
+
+module.exports = AndroidManifest;
+
+function capitalize (str) {
+    return str.charAt(0).toUpperCase() + str.slice(1);
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/AndroidProject.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/AndroidProject.js b/bin/templates/cordova/lib/AndroidProject.js
index 918a39b..458b84e 100644
--- a/bin/templates/cordova/lib/AndroidProject.js
+++ b/bin/templates/cordova/lib/AndroidProject.js
@@ -1,184 +1,184 @@
-/**
-    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 fs = require('fs');
-var path = require('path');
-var properties_parser = require('properties-parser');
-var AndroidManifest = require('./AndroidManifest');
-
-var projectFileCache = {};
-
-function addToPropertyList(projectProperties, key, value) {
-    var i = 1;
-    while (projectProperties.get(key + '.' + i))
-        i++;
-
-    projectProperties.set(key + '.' + i, value);
-    projectProperties.dirty = true;
-}
-
-function removeFromPropertyList(projectProperties, key, value) {
-    var i = 1;
-    var currentValue;
-    while ((currentValue = projectProperties.get(key + '.' + i))) {
-        if (currentValue === value) {
-            while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
-                projectProperties.set(key + '.' + i, currentValue);
-                i++;
-            }
-            projectProperties.set(key + '.' + i);
-            break;
-        }
-        i++;
-    }
-    projectProperties.dirty = true;
-}
-
-function getRelativeLibraryPath (parentDir, subDir) {
-    var libraryPath = path.relative(parentDir, subDir);
-    return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
-}
-
-function AndroidProject(projectDir) {
-    this._propertiesEditors = {};
-    this._subProjectDirs = {};
-    this._dirty = false;
-    this.projectDir = projectDir;
-    this.platformWww = path.join(this.projectDir, 'platform_www');
-    this.www = path.join(this.projectDir, 'assets/www');
-}
-
-AndroidProject.getProjectFile = function (projectDir) {
-    if (!projectFileCache[projectDir]) {
-        projectFileCache[projectDir] = new AndroidProject(projectDir);
-    }
-
-    return projectFileCache[projectDir];
-};
-
-AndroidProject.purgeCache = function (projectDir) {
-    if (projectDir) {
-        delete projectFileCache[projectDir];
-    } else {
-        projectFileCache = {};
-    }
-};
-
-/**
- * Reads the package name out of the Android Manifest file
- *
- * @param   {String}  projectDir  The absolute path to the directory containing the project
- *
- * @return  {String}              The name of the package
- */
-AndroidProject.prototype.getPackageName = function() {
-    return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
-};
-
-AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
-    // All custom subprojects are prefixed with the last portion of the package id.
-    // This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
-    var packageName = this.getPackageName();
-    var lastDotIndex = packageName.lastIndexOf('.');
-    var prefix = packageName.substring(lastDotIndex + 1);
-    var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
-    return subRelativeDir;
-};
-
-AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var subProjectFile = path.resolve(subDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    // TODO: Setting the target needs to happen only for pre-3.7.0 projects
-    if (fs.existsSync(subProjectFile)) {
-        var subProperties = this._getPropertiesFile(subProjectFile);
-        subProperties.set('target', parentProperties.get('target'));
-        subProperties.dirty = true;
-        this._subProjectDirs[subDir] = true;
-    }
-    addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
-
-    this._dirty = true;
-};
-
-AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
-    delete this._subProjectDirs[subDir];
-    this._dirty = true;
-};
-
-AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
-    this._dirty = true;
-};
-
-AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
-    this._dirty = true;
-};
-
-AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    addToPropertyList(parentProperties, 'cordova.system.library', value);
-    this._dirty = true;
-};
-
-AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
-    var parentProjectFile = path.resolve(parentDir, 'project.properties');
-    var parentProperties = this._getPropertiesFile(parentProjectFile);
-    removeFromPropertyList(parentProperties, 'cordova.system.library', value);
-    this._dirty = true;
-};
-
-AndroidProject.prototype.write = function() {
-    if (!this._dirty) {
-        return;
-    }
-    this._dirty = false;
-
-    for (var filename in this._propertiesEditors) {
-        var editor = this._propertiesEditors[filename];
-        if (editor.dirty) {
-            fs.writeFileSync(filename, editor.toString());
-            editor.dirty = false;
-        }
-    }
-};
-
-AndroidProject.prototype._getPropertiesFile = function (filename) {
-    if (!this._propertiesEditors[filename]) {
-        if (fs.existsSync(filename)) {
-            this._propertiesEditors[filename] = properties_parser.createEditor(filename);
-        } else {
-            this._propertiesEditors[filename] = properties_parser.createEditor();
-        }
-    }
-
-    return this._propertiesEditors[filename];
-};
-
-
-module.exports = AndroidProject;
+/**
+    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 fs = require('fs');
+var path = require('path');
+var properties_parser = require('properties-parser');
+var AndroidManifest = require('./AndroidManifest');
+
+var projectFileCache = {};
+
+function addToPropertyList(projectProperties, key, value) {
+    var i = 1;
+    while (projectProperties.get(key + '.' + i))
+        i++;
+
+    projectProperties.set(key + '.' + i, value);
+    projectProperties.dirty = true;
+}
+
+function removeFromPropertyList(projectProperties, key, value) {
+    var i = 1;
+    var currentValue;
+    while ((currentValue = projectProperties.get(key + '.' + i))) {
+        if (currentValue === value) {
+            while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
+                projectProperties.set(key + '.' + i, currentValue);
+                i++;
+            }
+            projectProperties.set(key + '.' + i);
+            break;
+        }
+        i++;
+    }
+    projectProperties.dirty = true;
+}
+
+function getRelativeLibraryPath (parentDir, subDir) {
+    var libraryPath = path.relative(parentDir, subDir);
+    return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
+}
+
+function AndroidProject(projectDir) {
+    this._propertiesEditors = {};
+    this._subProjectDirs = {};
+    this._dirty = false;
+    this.projectDir = projectDir;
+    this.platformWww = path.join(this.projectDir, 'platform_www');
+    this.www = path.join(this.projectDir, 'assets/www');
+}
+
+AndroidProject.getProjectFile = function (projectDir) {
+    if (!projectFileCache[projectDir]) {
+        projectFileCache[projectDir] = new AndroidProject(projectDir);
+    }
+
+    return projectFileCache[projectDir];
+};
+
+AndroidProject.purgeCache = function (projectDir) {
+    if (projectDir) {
+        delete projectFileCache[projectDir];
+    } else {
+        projectFileCache = {};
+    }
+};
+
+/**
+ * Reads the package name out of the Android Manifest file
+ *
+ * @param   {String}  projectDir  The absolute path to the directory containing the project
+ *
+ * @return  {String}              The name of the package
+ */
+AndroidProject.prototype.getPackageName = function() {
+    return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
+};
+
+AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
+    // All custom subprojects are prefixed with the last portion of the package id.
+    // This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
+    var packageName = this.getPackageName();
+    var lastDotIndex = packageName.lastIndexOf('.');
+    var prefix = packageName.substring(lastDotIndex + 1);
+    var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
+    return subRelativeDir;
+};
+
+AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var subProjectFile = path.resolve(subDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    // TODO: Setting the target needs to happen only for pre-3.7.0 projects
+    if (fs.existsSync(subProjectFile)) {
+        var subProperties = this._getPropertiesFile(subProjectFile);
+        subProperties.set('target', parentProperties.get('target'));
+        subProperties.dirty = true;
+        this._subProjectDirs[subDir] = true;
+    }
+    addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+    delete this._subProjectDirs[subDir];
+    this._dirty = true;
+};
+
+AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+    this._dirty = true;
+};
+
+AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    addToPropertyList(parentProperties, 'cordova.system.library', value);
+    this._dirty = true;
+};
+
+AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
+    var parentProjectFile = path.resolve(parentDir, 'project.properties');
+    var parentProperties = this._getPropertiesFile(parentProjectFile);
+    removeFromPropertyList(parentProperties, 'cordova.system.library', value);
+    this._dirty = true;
+};
+
+AndroidProject.prototype.write = function() {
+    if (!this._dirty) {
+        return;
+    }
+    this._dirty = false;
+
+    for (var filename in this._propertiesEditors) {
+        var editor = this._propertiesEditors[filename];
+        if (editor.dirty) {
+            fs.writeFileSync(filename, editor.toString());
+            editor.dirty = false;
+        }
+    }
+};
+
+AndroidProject.prototype._getPropertiesFile = function (filename) {
+    if (!this._propertiesEditors[filename]) {
+        if (fs.existsSync(filename)) {
+            this._propertiesEditors[filename] = properties_parser.createEditor(filename);
+        } else {
+            this._propertiesEditors[filename] = properties_parser.createEditor();
+        }
+    }
+
+    return this._propertiesEditors[filename];
+};
+
+
+module.exports = AndroidProject;

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/ConsoleLogger.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/ConsoleLogger.js b/bin/templates/cordova/lib/ConsoleLogger.js
index 19b03ec..cee2dc1 100644
--- a/bin/templates/cordova/lib/ConsoleLogger.js
+++ b/bin/templates/cordova/lib/ConsoleLogger.js
@@ -1,75 +1,75 @@
-/**
-    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 loggerInstance;
-var util = require('util');
-var EventEmitter = require('events').EventEmitter;
-var CordovaError = require('cordova-common').CordovaError;
-
-/**
- * @class ConsoleLogger
- * @extends EventEmitter
- *
- * Implementing basic logging for platform. Inherits regular NodeJS
- *   EventEmitter. All events, emitted on this class instance are immediately
- *   logged to console.
- *
- * Also attaches handler to process' uncaught exceptions, so these exceptions
- *   logged to console similar to regular error events.
- */
-function ConsoleLogger() {
-    EventEmitter.call(this);
-
-    var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
-    // For CordovaError print only the message without stack trace unless we
-    // are in a verbose mode.
-    process.on('uncaughtException', function(err){
-        if ((err instanceof CordovaError) && isVerbose) {
-            console.error(err.stack);
-        } else {
-            console.error(err.message);
-        }
-        process.exit(1);
-    });
-
-    this.on('results', console.log);
-    this.on('verbose', function () {
-        if (isVerbose)
-            console.log.apply(console, arguments);
-    });
-    this.on('info', console.log);
-    this.on('log', console.log);
-    this.on('warn', console.warn);
-}
-util.inherits(ConsoleLogger, EventEmitter);
-
-/**
- * Returns already instantiated/newly created instance of ConsoleLogger class.
- *   This method should be used instead of creating ConsoleLogger directly,
- *   otherwise we'll get multiple handlers attached to process'
- *   uncaughtException
- *
- * @return  {ConsoleLogger}  New or already created instance of ConsoleLogger
- */
-ConsoleLogger.get = function () {
-    loggerInstance = loggerInstance || new ConsoleLogger();
-    return loggerInstance;
-};
-
-module.exports = ConsoleLogger;
+/**
+    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 loggerInstance;
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var CordovaError = require('cordova-common').CordovaError;
+
+/**
+ * @class ConsoleLogger
+ * @extends EventEmitter
+ *
+ * Implementing basic logging for platform. Inherits regular NodeJS
+ *   EventEmitter. All events, emitted on this class instance are immediately
+ *   logged to console.
+ *
+ * Also attaches handler to process' uncaught exceptions, so these exceptions
+ *   logged to console similar to regular error events.
+ */
+function ConsoleLogger() {
+    EventEmitter.call(this);
+
+    var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
+    // For CordovaError print only the message without stack trace unless we
+    // are in a verbose mode.
+    process.on('uncaughtException', function(err){
+        if ((err instanceof CordovaError) && isVerbose) {
+            console.error(err.stack);
+        } else {
+            console.error(err.message);
+        }
+        process.exit(1);
+    });
+
+    this.on('results', console.log);
+    this.on('verbose', function () {
+        if (isVerbose)
+            console.log.apply(console, arguments);
+    });
+    this.on('info', console.log);
+    this.on('log', console.log);
+    this.on('warn', console.warn);
+}
+util.inherits(ConsoleLogger, EventEmitter);
+
+/**
+ * Returns already instantiated/newly created instance of ConsoleLogger class.
+ *   This method should be used instead of creating ConsoleLogger directly,
+ *   otherwise we'll get multiple handlers attached to process'
+ *   uncaughtException
+ *
+ * @return  {ConsoleLogger}  New or already created instance of ConsoleLogger
+ */
+ConsoleLogger.get = function () {
+    loggerInstance = loggerInstance || new ConsoleLogger();
+    return loggerInstance;
+};
+
+module.exports = ConsoleLogger;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[4/4] android commit: Fixed line endings

Posted by st...@apache.org.
Fixed line endings


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/0ac822c5
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/0ac822c5
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/0ac822c5

Branch: refs/heads/master
Commit: 0ac822c57737ddf0a252b5da6406eef3ba426285
Parents: 4002822
Author: Steve Gill <st...@gmail.com>
Authored: Tue Oct 20 16:15:57 2015 -0700
Committer: Steve Gill <st...@gmail.com>
Committed: Tue Oct 20 16:15:57 2015 -0700

----------------------------------------------------------------------
 LICENSE                                         |   2 +-
 bin/check_reqs.bat                              |   4 +-
 bin/create                                      | 112 +--
 bin/lib/check_reqs.js                           | 652 ++++++------
 bin/lib/create.js                               | 664 ++++++-------
 bin/templates/cordova/Api.js                    | 984 +++++++++----------
 bin/templates/cordova/lib/Adb.js                | 156 +--
 bin/templates/cordova/lib/AndroidManifest.js    | 322 +++---
 bin/templates/cordova/lib/AndroidProject.js     | 368 +++----
 bin/templates/cordova/lib/ConsoleLogger.js      | 150 +--
 bin/templates/cordova/lib/build.js              | 602 ++++++------
 .../cordova/lib/builders/AntBuilder.js          | 282 +++---
 .../cordova/lib/builders/GradleBuilder.js       | 426 ++++----
 bin/templates/cordova/lib/device.js             | 212 ++--
 bin/templates/cordova/lib/emulator.js           | 744 +++++++-------
 bin/templates/cordova/lib/pluginHandlers.js     | 504 +++++-----
 bin/templates/cordova/lib/prepare.js            | 728 +++++++-------
 bin/update                                      |  70 +-
 package.json                                    |  92 +-
 19 files changed, 3537 insertions(+), 3537 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index fd26dc7..c47288d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-
+
                                  Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/check_reqs.bat
----------------------------------------------------------------------
diff --git a/bin/check_reqs.bat b/bin/check_reqs.bat
index cb2c6f5..fd7b7d1 100644
--- a/bin/check_reqs.bat
+++ b/bin/check_reqs.bat
@@ -5,9 +5,9 @@
 :: 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

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/create
----------------------------------------------------------------------
diff --git a/bin/create b/bin/create
index bdbbc80..2052a27 100755
--- a/bin/create
+++ b/bin/create
@@ -1,56 +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');
-var ConfigParser = require('cordova-common').ConfigParser;
-var Api = require('./templates/cordova/Api');
-
-var argv = require('nopt')({
-    'help' : Boolean,
-    'cli' : Boolean,
-    'shared' : Boolean,
-    'link' : Boolean,
-    'activity-name' : [String, undefined]
-});
-
-if (argv.help || argv.argv.remain.length === 0) {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
-    console.log('    <path_to_new_project>: Path to your new Cordova Android project');
-    console.log('    <package_name>: Package name, following reverse-domain style convention');
-    console.log('    <project_name>: Project name');
-    console.log('    <template_path>: Path to a custom application template to use');
-    console.log('    --activity-name <activity_name>: Activity name');
-    console.log('    --link will use the CordovaLib project directly instead of making a copy.');
-    process.exit(1);
-}
-
-var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
-
-if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
-if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
-if (argv['activity-name']) config.setName(argv['activity-name']);
-
-var options = {
-    link: argv.link || argv.shared,
-    customTemplate: argv.argv.remain[3],
-    activityName: argv['activity-name']
-};
-
-Api.createPlatform(argv.argv.remain[0], config, options).done();
+#!/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 ConfigParser = require('cordova-common').ConfigParser;
+var Api = require('./templates/cordova/Api');
+
+var argv = require('nopt')({
+    'help' : Boolean,
+    'cli' : Boolean,
+    'shared' : Boolean,
+    'link' : Boolean,
+    'activity-name' : [String, undefined]
+});
+
+if (argv.help || argv.argv.remain.length === 0) {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
+    console.log('    <path_to_new_project>: Path to your new Cordova Android project');
+    console.log('    <package_name>: Package name, following reverse-domain style convention');
+    console.log('    <project_name>: Project name');
+    console.log('    <template_path>: Path to a custom application template to use');
+    console.log('    --activity-name <activity_name>: Activity name');
+    console.log('    --link will use the CordovaLib project directly instead of making a copy.');
+    process.exit(1);
+}
+
+var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
+
+if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
+if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
+if (argv['activity-name']) config.setName(argv['activity-name']);
+
+var options = {
+    link: argv.link || argv.shared,
+    customTemplate: argv.argv.remain[3],
+    activityName: argv['activity-name']
+};
+
+Api.createPlatform(argv.argv.remain[0], config, options).done();

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/bin/lib/check_reqs.js b/bin/lib/check_reqs.js
index 57e1f47..d3a93e1 100644
--- a/bin/lib/check_reqs.js
+++ b/bin/lib/check_reqs.js
@@ -1,326 +1,326 @@
-#!/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'),
-    ROOT  = path.join(__dirname, '..', '..');
-var CordovaError = require('cordova-common').CordovaError;
-
-var isWindows = process.platform == 'win32';
-
-function forgivingWhichSync(cmd) {
-    try {
-        return fs.realpathSync(shelljs.which(cmd));
-    } catch (e) {
-        return '';
-    }
-}
-
-function tryCommand(cmd, errMsg, catchStderr) {
-    var d = Q.defer();
-    child_process.exec(cmd, function(err, stdout, stderr) {
-        if (err) d.reject(new CordovaError(errMsg));
-        // Sometimes it is necessary to return an stderr instead of stdout in case of success, since
-        // some commands prints theirs output to stderr instead of stdout. 'javac' is the example
-        else d.resolve((catchStderr ? stderr : stdout).trim());
-    });
-    return d.promise;
-}
-
-// 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(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
-            'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
-
-    var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
-    if (!fs.existsSync(wrapperDir)) {
-        return Q.reject(new CordovaError('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 CordovaError(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 CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
-                    'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
-                    'Try reinstall Android SDK or update your PATH to include 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 CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
-                'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
-        }
-        if (!fs.existsSync(process.env['ANDROID_HOME'])) {
-            throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
-                '\nTry update it manually to point to valid SDK directory.');
-        }
-    });
-};
-
-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 CordovaError('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;
-    });
-};
+#!/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'),
+    ROOT  = path.join(__dirname, '..', '..');
+var CordovaError = require('cordova-common').CordovaError;
+
+var isWindows = process.platform == 'win32';
+
+function forgivingWhichSync(cmd) {
+    try {
+        return fs.realpathSync(shelljs.which(cmd));
+    } catch (e) {
+        return '';
+    }
+}
+
+function tryCommand(cmd, errMsg, catchStderr) {
+    var d = Q.defer();
+    child_process.exec(cmd, function(err, stdout, stderr) {
+        if (err) d.reject(new CordovaError(errMsg));
+        // Sometimes it is necessary to return an stderr instead of stdout in case of success, since
+        // some commands prints theirs output to stderr instead of stdout. 'javac' is the example
+        else d.resolve((catchStderr ? stderr : stdout).trim());
+    });
+    return d.promise;
+}
+
+// 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(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
+            'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
+
+    var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
+    if (!fs.existsSync(wrapperDir)) {
+        return Q.reject(new CordovaError('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 CordovaError(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 CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+                    'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
+                    'Try reinstall Android SDK or update your PATH to include 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 CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
+                'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
+        }
+        if (!fs.existsSync(process.env['ANDROID_HOME'])) {
+            throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
+                '\nTry update it manually to point to valid SDK directory.');
+        }
+    });
+};
+
+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 CordovaError('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;
+    });
+};

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index 799836f..9d4b4ae 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -1,332 +1,332 @@
-#!/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 shell = require('shelljs'),
-    Q     = require('q'),
-    path  = require('path'),
-    fs    = require('fs'),
-    check_reqs = require('./check_reqs'),
-    ROOT    = path.join(__dirname, '..', '..');
-
-var MIN_SDK_VERSION = 14;
-
-var CordovaError = require('cordova-common').CordovaError;
-var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
-
-function setShellFatal(value, func) {
-    var oldVal = shell.config.fatal;
-    shell.config.fatal = value;
-    func();
-    shell.config.fatal = oldVal;
-}
-
-function getFrameworkDir(projectPath, shared) {
-    return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
-}
-
-function copyJsAndLibrary(projectPath, shared, projectName) {
-    var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
-    var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
-    shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
-
-    // Copy the cordova.js file to platforms/<platform>/platform_www/
-    // The www dir is nuked on each prepare so we keep cordova.js in platform_www
-    shell.mkdir('-p', path.join(projectPath, 'platform_www'));
-    shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
-
-    // Copy cordova-js-src directory into platform_www directory.
-    // We need these files to build cordova.js if using browserify method.
-    shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
-
-    // Don't fail if there are no old jars.
-    setShellFatal(false, function() {
-        shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
-            console.log('Deleting ' + oldJar);
-            shell.rm('-f', oldJar);
-        });
-        var wasSymlink = true;
-        try {
-            // Delete the symlink if it was one.
-            fs.unlinkSync(nestedCordovaLibPath);
-        } catch (e) {
-            wasSymlink = false;
-        }
-        // Delete old library project if it existed.
-        if (shared) {
-            shell.rm('-rf', nestedCordovaLibPath);
-        } else if (!wasSymlink) {
-            // Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
-            shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
-        }
-    });
-    if (shared) {
-        var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
-        fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
-    } else {
-        shell.mkdir('-p', nestedCordovaLibPath);
-        shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
-        shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
-        shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
-        shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
-        shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
-    }
-}
-
-function extractSubProjectPaths(data) {
-    var ret = {};
-    var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
-    var m;
-    while ((m = r.exec(data))) {
-        ret[m[1]] = 1;
-    }
-    return Object.keys(ret);
-}
-
-function writeProjectProperties(projectPath, target_api) {
-    var dstPath = path.join(projectPath, 'project.properties');
-    var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
-    var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
-
-    var data = fs.readFileSync(srcPath, 'utf8');
-    data = data.replace(/^target=.*/m, 'target=' + target_api);
-    var subProjects = extractSubProjectPaths(data);
-    subProjects = subProjects.filter(function(p) {
-        return !(/^CordovaLib$/m.exec(p) ||
-                 /[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
-                 /^(\.\.[\\\/])+framework$/m.exec(p)
-                 );
-    });
-    subProjects.unshift('CordovaLib');
-    data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
-    if (!/\n$/.exec(data)) {
-        data += '\n';
-    }
-    for (var i = 0; i < subProjects.length; ++i) {
-        data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
-    }
-    fs.writeFileSync(dstPath, data);
-}
-
-function prepBuildFiles(projectPath) {
-    var buildModule = require(path.join(path.resolve(projectPath), 'cordova', 'lib', 'build'));
-    buildModule.prepBuildFiles();
-}
-
-function copyBuildRules(projectPath) {
-    var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
-
-    shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
-}
-
-function copyScripts(projectPath) {
-    var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
-    var destScriptsDir = path.join(projectPath, 'cordova');
-    // Delete old scripts directory if this is an update.
-    shell.rm('-rf', destScriptsDir);
-    // Copy in the new ones.
-    shell.cp('-r', srcScriptsDir, projectPath);
-    shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
-    shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
-    shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
-    shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
-    shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
-}
-
-/**
- * Test whether a package name is acceptable for use as an android project.
- * Returns a promise, fulfilled if the package name is acceptable; rejected
- * otherwise.
- */
-function validatePackageName(package_name) {
-    //Make the package conform to Java package types
-    //http://developer.android.com/guide/topics/manifest/manifest-element.html#package
-    //Enforce underscore limitation
-    var msg = 'Error validating package name. ';
-    if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
-        return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
-    }
-
-    //Class is a reserved word
-    if(/\b[Cc]lass\b/.test(package_name)) {
-        return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
-    }
-
-    return Q.resolve();
-}
-
-/**
- * Test whether a project name is acceptable for use as an android class.
- * Returns a promise, fulfilled if the project name is acceptable; rejected
- * otherwise.
- */
-function validateProjectName(project_name) {
-    var msg = 'Error validating project name. ';
-    //Make sure there's something there
-    if (project_name === '') {
-        return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
-    }
-
-    //Enforce stupid name error
-    if (project_name === 'CordovaActivity') {
-        return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
-    }
-
-    //Classes in Java don't begin with numbers
-    if (/^[0-9]/.test(project_name)) {
-        return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
-    }
-
-    return Q.resolve();
-}
-
-/**
- * Creates an android application with the given options.
- *
- * @param   {String}  project_path  Path to the new Cordova android project.
- * @param   {ConfigParser}  config  Instance of ConfigParser to retrieve basic
- *   project properties.
- * @param   {Object}  [options={}]  Various options
- * @param   {String}  [options.activityName='MainActivity']  Name for the
- *   activity
- * @param   {Boolean}  [options.link=false]  Specifies whether javascript files
- *   and CordovaLib framework will be symlinked to created application.
- * @param   {String}  [options.customTemplate]  Path to project template
- *   (override)
- * @param   {EventEmitter}  [events]  An EventEmitter instance for logging
- *   events
- *
- * @return  {Promise<String>}  Directory where application has been created
- */
-exports.create = function(project_path, config, options, events) {
-
-    options = options || {};
-
-    // Set default values for path, package and name
-    project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
-    // Check if project already exists
-    if(fs.existsSync(project_path)) {
-        return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
-    }
-
-    var package_name = config.packageName() || 'my.cordova.project';
-    var project_name = config.name() ?
-        config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
-
-    var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
-    var target_api      = check_reqs.get_target();
-
-    //Make the package conform to Java package types
-    return validatePackageName(package_name)
-    .then(function() {
-        validateProjectName(project_name);
-    }).then(function() {
-        // Log the given values for the project
-        events.emit('log', 'Creating Cordova project for the Android platform:');
-        events.emit('log', '\tPath: ' + project_path);
-        events.emit('log', '\tPackage: ' + package_name);
-        events.emit('log', '\tName: ' + project_name);
-        events.emit('log', '\tActivity: ' + safe_activity_name);
-        events.emit('log', '\tAndroid target: ' + target_api);
-
-        events.emit('verbose', 'Copying template files...');
-
-        setShellFatal(true, function() {
-            var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
-            // copy project template
-            shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
-            shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
-            shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
-
-            // Manually create directories that would be empty within the template (since git doesn't track directories).
-            shell.mkdir(path.join(project_path, 'libs'));
-
-            // copy cordova.js, cordova.jar
-            copyJsAndLibrary(project_path, options.link, safe_activity_name);
-
-            // interpolate the activity name and package
-            var packagePath = package_name.replace(/\./g, path.sep);
-            var activity_dir = path.join(project_path, 'src', packagePath);
-            var activity_path = path.join(activity_dir, safe_activity_name + '.java');
-            shell.mkdir('-p', activity_dir);
-            shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
-            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
-            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
-            shell.sed('-i', /__ID__/, package_name, activity_path);
-
-            var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
-            manifest.setPackageId(package_name)
-                .setTargetSdkVersion(target_api.split('-')[1])
-                .getActivity().setName(safe_activity_name);
-
-            var manifest_path = path.join(project_path, 'AndroidManifest.xml');
-            manifest.write(manifest_path);
-
-            copyScripts(project_path);
-            copyBuildRules(project_path);
-        });
-        // Link it to local android install.
-        writeProjectProperties(project_path, target_api);
-        prepBuildFiles(project_path);
-        events.emit('log', generateDoneMessage('create', options.link));
-    }).thenResolve(project_path);
-};
-
-function generateDoneMessage(type, link) {
-    var pkg = require('../../package');
-    var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
-    if (link) {
-        msg += ' and has a linked CordovaLib';
-    }
-    return msg;
-}
-
-// Returns a promise.
-exports.update = function(projectPath, options, events) {
-    options = options || {};
-
-    return Q()
-    .then(function() {
-
-        var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
-
-        if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
-            events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
-            manifest.setMinSDKVersion(MIN_SDK_VERSION);
-        }
-
-        manifest.setDebuggable(false).write();
-
-        var projectName = manifest.getActivity().getName();
-        var target_api = check_reqs.get_target();
-
-        copyJsAndLibrary(projectPath, options.link, projectName);
-        copyScripts(projectPath);
-        copyBuildRules(projectPath);
-        writeProjectProperties(projectPath, target_api);
-        prepBuildFiles(projectPath);
-        events.emit('log', generateDoneMessage('update', options.link));
-    }).thenResolve(projectPath);
-};
-
-
-// For testing
-exports.validatePackageName = validatePackageName;
-exports.validateProjectName = validateProjectName;
+#!/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 shell = require('shelljs'),
+    Q     = require('q'),
+    path  = require('path'),
+    fs    = require('fs'),
+    check_reqs = require('./check_reqs'),
+    ROOT    = path.join(__dirname, '..', '..');
+
+var MIN_SDK_VERSION = 14;
+
+var CordovaError = require('cordova-common').CordovaError;
+var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
+
+function setShellFatal(value, func) {
+    var oldVal = shell.config.fatal;
+    shell.config.fatal = value;
+    func();
+    shell.config.fatal = oldVal;
+}
+
+function getFrameworkDir(projectPath, shared) {
+    return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
+}
+
+function copyJsAndLibrary(projectPath, shared, projectName) {
+    var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
+    var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
+    shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
+
+    // Copy the cordova.js file to platforms/<platform>/platform_www/
+    // The www dir is nuked on each prepare so we keep cordova.js in platform_www
+    shell.mkdir('-p', path.join(projectPath, 'platform_www'));
+    shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
+
+    // Copy cordova-js-src directory into platform_www directory.
+    // We need these files to build cordova.js if using browserify method.
+    shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
+
+    // Don't fail if there are no old jars.
+    setShellFatal(false, function() {
+        shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
+            console.log('Deleting ' + oldJar);
+            shell.rm('-f', oldJar);
+        });
+        var wasSymlink = true;
+        try {
+            // Delete the symlink if it was one.
+            fs.unlinkSync(nestedCordovaLibPath);
+        } catch (e) {
+            wasSymlink = false;
+        }
+        // Delete old library project if it existed.
+        if (shared) {
+            shell.rm('-rf', nestedCordovaLibPath);
+        } else if (!wasSymlink) {
+            // Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
+            shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
+        }
+    });
+    if (shared) {
+        var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
+        fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
+    } else {
+        shell.mkdir('-p', nestedCordovaLibPath);
+        shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
+        shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
+        shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
+        shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
+        shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
+    }
+}
+
+function extractSubProjectPaths(data) {
+    var ret = {};
+    var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
+    var m;
+    while ((m = r.exec(data))) {
+        ret[m[1]] = 1;
+    }
+    return Object.keys(ret);
+}
+
+function writeProjectProperties(projectPath, target_api) {
+    var dstPath = path.join(projectPath, 'project.properties');
+    var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
+    var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
+
+    var data = fs.readFileSync(srcPath, 'utf8');
+    data = data.replace(/^target=.*/m, 'target=' + target_api);
+    var subProjects = extractSubProjectPaths(data);
+    subProjects = subProjects.filter(function(p) {
+        return !(/^CordovaLib$/m.exec(p) ||
+                 /[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
+                 /^(\.\.[\\\/])+framework$/m.exec(p)
+                 );
+    });
+    subProjects.unshift('CordovaLib');
+    data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
+    if (!/\n$/.exec(data)) {
+        data += '\n';
+    }
+    for (var i = 0; i < subProjects.length; ++i) {
+        data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
+    }
+    fs.writeFileSync(dstPath, data);
+}
+
+function prepBuildFiles(projectPath) {
+    var buildModule = require(path.join(path.resolve(projectPath), 'cordova', 'lib', 'build'));
+    buildModule.prepBuildFiles();
+}
+
+function copyBuildRules(projectPath) {
+    var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
+
+    shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
+}
+
+function copyScripts(projectPath) {
+    var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
+    var destScriptsDir = path.join(projectPath, 'cordova');
+    // Delete old scripts directory if this is an update.
+    shell.rm('-rf', destScriptsDir);
+    // Copy in the new ones.
+    shell.cp('-r', srcScriptsDir, projectPath);
+    shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
+    shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
+    shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
+    shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
+    shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
+}
+
+/**
+ * Test whether a package name is acceptable for use as an android project.
+ * Returns a promise, fulfilled if the package name is acceptable; rejected
+ * otherwise.
+ */
+function validatePackageName(package_name) {
+    //Make the package conform to Java package types
+    //http://developer.android.com/guide/topics/manifest/manifest-element.html#package
+    //Enforce underscore limitation
+    var msg = 'Error validating package name. ';
+    if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
+        return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
+    }
+
+    //Class is a reserved word
+    if(/\b[Cc]lass\b/.test(package_name)) {
+        return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
+    }
+
+    return Q.resolve();
+}
+
+/**
+ * Test whether a project name is acceptable for use as an android class.
+ * Returns a promise, fulfilled if the project name is acceptable; rejected
+ * otherwise.
+ */
+function validateProjectName(project_name) {
+    var msg = 'Error validating project name. ';
+    //Make sure there's something there
+    if (project_name === '') {
+        return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
+    }
+
+    //Enforce stupid name error
+    if (project_name === 'CordovaActivity') {
+        return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
+    }
+
+    //Classes in Java don't begin with numbers
+    if (/^[0-9]/.test(project_name)) {
+        return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
+    }
+
+    return Q.resolve();
+}
+
+/**
+ * Creates an android application with the given options.
+ *
+ * @param   {String}  project_path  Path to the new Cordova android project.
+ * @param   {ConfigParser}  config  Instance of ConfigParser to retrieve basic
+ *   project properties.
+ * @param   {Object}  [options={}]  Various options
+ * @param   {String}  [options.activityName='MainActivity']  Name for the
+ *   activity
+ * @param   {Boolean}  [options.link=false]  Specifies whether javascript files
+ *   and CordovaLib framework will be symlinked to created application.
+ * @param   {String}  [options.customTemplate]  Path to project template
+ *   (override)
+ * @param   {EventEmitter}  [events]  An EventEmitter instance for logging
+ *   events
+ *
+ * @return  {Promise<String>}  Directory where application has been created
+ */
+exports.create = function(project_path, config, options, events) {
+
+    options = options || {};
+
+    // Set default values for path, package and name
+    project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
+    // Check if project already exists
+    if(fs.existsSync(project_path)) {
+        return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
+    }
+
+    var package_name = config.packageName() || 'my.cordova.project';
+    var project_name = config.name() ?
+        config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
+
+    var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
+    var target_api      = check_reqs.get_target();
+
+    //Make the package conform to Java package types
+    return validatePackageName(package_name)
+    .then(function() {
+        validateProjectName(project_name);
+    }).then(function() {
+        // Log the given values for the project
+        events.emit('log', 'Creating Cordova project for the Android platform:');
+        events.emit('log', '\tPath: ' + project_path);
+        events.emit('log', '\tPackage: ' + package_name);
+        events.emit('log', '\tName: ' + project_name);
+        events.emit('log', '\tActivity: ' + safe_activity_name);
+        events.emit('log', '\tAndroid target: ' + target_api);
+
+        events.emit('verbose', 'Copying template files...');
+
+        setShellFatal(true, function() {
+            var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
+            // copy project template
+            shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
+            shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
+            shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
+
+            // Manually create directories that would be empty within the template (since git doesn't track directories).
+            shell.mkdir(path.join(project_path, 'libs'));
+
+            // copy cordova.js, cordova.jar
+            copyJsAndLibrary(project_path, options.link, safe_activity_name);
+
+            // interpolate the activity name and package
+            var packagePath = package_name.replace(/\./g, path.sep);
+            var activity_dir = path.join(project_path, 'src', packagePath);
+            var activity_path = path.join(activity_dir, safe_activity_name + '.java');
+            shell.mkdir('-p', activity_dir);
+            shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
+            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
+            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
+            shell.sed('-i', /__ID__/, package_name, activity_path);
+
+            var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
+            manifest.setPackageId(package_name)
+                .setTargetSdkVersion(target_api.split('-')[1])
+                .getActivity().setName(safe_activity_name);
+
+            var manifest_path = path.join(project_path, 'AndroidManifest.xml');
+            manifest.write(manifest_path);
+
+            copyScripts(project_path);
+            copyBuildRules(project_path);
+        });
+        // Link it to local android install.
+        writeProjectProperties(project_path, target_api);
+        prepBuildFiles(project_path);
+        events.emit('log', generateDoneMessage('create', options.link));
+    }).thenResolve(project_path);
+};
+
+function generateDoneMessage(type, link) {
+    var pkg = require('../../package');
+    var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
+    if (link) {
+        msg += ' and has a linked CordovaLib';
+    }
+    return msg;
+}
+
+// Returns a promise.
+exports.update = function(projectPath, options, events) {
+    options = options || {};
+
+    return Q()
+    .then(function() {
+
+        var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
+
+        if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
+            events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
+            manifest.setMinSDKVersion(MIN_SDK_VERSION);
+        }
+
+        manifest.setDebuggable(false).write();
+
+        var projectName = manifest.getActivity().getName();
+        var target_api = check_reqs.get_target();
+
+        copyJsAndLibrary(projectPath, options.link, projectName);
+        copyScripts(projectPath);
+        copyBuildRules(projectPath);
+        writeProjectProperties(projectPath, target_api);
+        prepBuildFiles(projectPath);
+        events.emit('log', generateDoneMessage('update', options.link));
+    }).thenResolve(projectPath);
+};
+
+
+// For testing
+exports.validatePackageName = validatePackageName;
+exports.validateProjectName = validateProjectName;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[2/4] android commit: Fixed line endings

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js
index db692e9..9e57cb8 100644
--- a/bin/templates/cordova/lib/build.js
+++ b/bin/templates/cordova/lib/build.js
@@ -1,301 +1,301 @@
-#!/usr/bin/env node
-
-/*
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
-*/
-
-var Q       = require('q'),
-    path    = require('path'),
-    fs      = require('fs'),
-    nopt = require('nopt');
-
-var Adb = require('./Adb');
-
-var builders = require('./builders/builders');
-var events = require('cordova-common').events;
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-
-function parseOpts(options, resolvedTarget) {
-    options = options || {};
-    options.argv = nopt({
-        gradle: Boolean,
-        ant: Boolean,
-        prepenv: Boolean,
-        versionCode: String,
-        minSdkVersion: String,
-        gradleArg: String,
-        keystore: path,
-        alias: String,
-        storePassword: String,
-        password: String,
-        keystoreType: String
-    }, {}, options.argv, 0);
-
-    var ret = {
-        buildType: options.release ? 'release' : 'debug',
-        buildMethod: process.env.ANDROID_BUILD || 'gradle',
-        prepEnv: options.argv.prepenv,
-        arch: resolvedTarget && resolvedTarget.arch,
-        extraArgs: []
-    };
-
-    if (options.argv.ant || options.argv.gradle)
-        ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
-
-    if (options.nobuild) ret.buildMethod = 'none';
-
-    if (options.argv.versionCode)
-        ret.extraArgs.push('-PcdvVersionCode=' + options.versionCode);
-
-    if (options.argv.minSdkVersion)
-        ret.extraArgs.push('-PcdvMinSdkVersion=' + options.minSdkVersion);
-
-    if (options.argv.gradleArg)
-        ret.extraArgs.push(options.gradleArg);
-
-    var packageArgs = {};
-
-    if (options.argv.keystore)
-        packageArgs.keystore = path.relative(this.root, path.resolve(options.argv.keystore));
-
-    ['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
-        if (options.argv[flagName])
-            packageArgs[flagName] = options.argv[flagName];
-    });
-
-    var buildConfig = options.buildConfig;
-
-    // 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);
-        }
-        events.emit('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) {
-                packageArgs.keystore = path.resolve(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) {
-            events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
-        }
-    }
-
-    return ret;
-}
-
-/*
- * Builds the project with the specifed options
- * Returns a promise.
- */
-module.exports.runClean = function(options) {
-    var opts = parseOpts(options);
-    var builder = builders.getBuilder(opts.buildMethod);
-    return builder.prepEnv(opts)
-    .then(function() {
-        return builder.clean(opts);
-    });
-};
-
-/**
- * Builds the project with the specifed options.
- *
- * @param   {BuildOptions}  options      A set of options. See PlatformApi.build
- *   method documentation for reference.
- * @param   {Object}  optResolvedTarget  A deployment target. Used to pass
- *   target architecture from upstream 'run' call. TODO: remove this option in
- *   favor of setting buildOptions.archs field.
- *
- * @return  {Promise<Object>}            Promise, resolved with built packages
- *   information.
- */
-module.exports.run = function(options, optResolvedTarget) {
-    var opts = parseOpts(options, optResolvedTarget);
-    var builder = builders.getBuilder(opts.buildMethod);
-    var self = this;
-    return builder.prepEnv(opts)
-    .then(function() {
-        if (opts.prepEnv) {
-            self.events.emit('verbose', 'Build file successfully prepared.');
-            return;
-        }
-        return builder.build(opts)
-        .then(function() {
-            var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
-            self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
-            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() {
-    return builders.getBuilder('gradle').prepBuildFiles();
-};
-
-/*
- * Detects the architecture of a device/emulator
- * Returns "arm" or "x86".
- */
-module.exports.detectArchitecture = function(target) {
-    function helper() {
-        return Adb.shell(target, 'cat /proc/cpuinfo')
-        .then(function(output) {
-            return /intel/i.exec(output) ? 'x86' : '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, new CordovaError('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 spawn('killall', ['adb'])
-            .then(function() {
-                events.emit('verbose', 'adb seems hung. retrying.');
-                return helper()
-                .then(null, function() {
-                    // The double kill is sadly often necessary, at least on mac.
-                    events.emit('warn', 'Now device not found... restarting adb again.');
-                    return spawn('killall', ['adb'])
-                    .then(function() {
-                        return helper()
-                        .then(null, function() {
-                            return Q.reject(new CordovaError('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) {
-        var apkName = path.basename(p);
-        if (buildResults.buildType == 'debug') {
-            return /-debug/.exec(apkName);
-        }
-        return !/-debug/.exec(apkName);
-    });
-    var archPattern = new RegExp('-' + arch);
-    var hasArchPattern = /-x86|-arm/;
-    for (var i = 0; i < paths.length; ++i) {
-        var apkName = path.basename(paths[i]);
-        if (hasArchPattern.exec(apkName)) {
-            if (archPattern.exec(apkName)) {
-                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('../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);
-};
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Q       = require('q'),
+    path    = require('path'),
+    fs      = require('fs'),
+    nopt = require('nopt');
+
+var Adb = require('./Adb');
+
+var builders = require('./builders/builders');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+function parseOpts(options, resolvedTarget) {
+    options = options || {};
+    options.argv = nopt({
+        gradle: Boolean,
+        ant: Boolean,
+        prepenv: Boolean,
+        versionCode: String,
+        minSdkVersion: String,
+        gradleArg: String,
+        keystore: path,
+        alias: String,
+        storePassword: String,
+        password: String,
+        keystoreType: String
+    }, {}, options.argv, 0);
+
+    var ret = {
+        buildType: options.release ? 'release' : 'debug',
+        buildMethod: process.env.ANDROID_BUILD || 'gradle',
+        prepEnv: options.argv.prepenv,
+        arch: resolvedTarget && resolvedTarget.arch,
+        extraArgs: []
+    };
+
+    if (options.argv.ant || options.argv.gradle)
+        ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
+
+    if (options.nobuild) ret.buildMethod = 'none';
+
+    if (options.argv.versionCode)
+        ret.extraArgs.push('-PcdvVersionCode=' + options.versionCode);
+
+    if (options.argv.minSdkVersion)
+        ret.extraArgs.push('-PcdvMinSdkVersion=' + options.minSdkVersion);
+
+    if (options.argv.gradleArg)
+        ret.extraArgs.push(options.gradleArg);
+
+    var packageArgs = {};
+
+    if (options.argv.keystore)
+        packageArgs.keystore = path.relative(this.root, path.resolve(options.argv.keystore));
+
+    ['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
+        if (options.argv[flagName])
+            packageArgs[flagName] = options.argv[flagName];
+    });
+
+    var buildConfig = options.buildConfig;
+
+    // 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);
+        }
+        events.emit('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) {
+                packageArgs.keystore = path.resolve(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) {
+            events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * Builds the project with the specifed options
+ * Returns a promise.
+ */
+module.exports.runClean = function(options) {
+    var opts = parseOpts(options);
+    var builder = builders.getBuilder(opts.buildMethod);
+    return builder.prepEnv(opts)
+    .then(function() {
+        return builder.clean(opts);
+    });
+};
+
+/**
+ * Builds the project with the specifed options.
+ *
+ * @param   {BuildOptions}  options      A set of options. See PlatformApi.build
+ *   method documentation for reference.
+ * @param   {Object}  optResolvedTarget  A deployment target. Used to pass
+ *   target architecture from upstream 'run' call. TODO: remove this option in
+ *   favor of setting buildOptions.archs field.
+ *
+ * @return  {Promise<Object>}            Promise, resolved with built packages
+ *   information.
+ */
+module.exports.run = function(options, optResolvedTarget) {
+    var opts = parseOpts(options, optResolvedTarget);
+    var builder = builders.getBuilder(opts.buildMethod);
+    var self = this;
+    return builder.prepEnv(opts)
+    .then(function() {
+        if (opts.prepEnv) {
+            self.events.emit('verbose', 'Build file successfully prepared.');
+            return;
+        }
+        return builder.build(opts)
+        .then(function() {
+            var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
+            self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
+            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() {
+    return builders.getBuilder('gradle').prepBuildFiles();
+};
+
+/*
+ * Detects the architecture of a device/emulator
+ * Returns "arm" or "x86".
+ */
+module.exports.detectArchitecture = function(target) {
+    function helper() {
+        return Adb.shell(target, 'cat /proc/cpuinfo')
+        .then(function(output) {
+            return /intel/i.exec(output) ? 'x86' : '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, new CordovaError('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 spawn('killall', ['adb'])
+            .then(function() {
+                events.emit('verbose', 'adb seems hung. retrying.');
+                return helper()
+                .then(null, function() {
+                    // The double kill is sadly often necessary, at least on mac.
+                    events.emit('warn', 'Now device not found... restarting adb again.');
+                    return spawn('killall', ['adb'])
+                    .then(function() {
+                        return helper()
+                        .then(null, function() {
+                            return Q.reject(new CordovaError('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) {
+        var apkName = path.basename(p);
+        if (buildResults.buildType == 'debug') {
+            return /-debug/.exec(apkName);
+        }
+        return !/-debug/.exec(apkName);
+    });
+    var archPattern = new RegExp('-' + arch);
+    var hasArchPattern = /-x86|-arm/;
+    for (var i = 0; i < paths.length; ++i) {
+        var apkName = path.basename(paths[i]);
+        if (hasArchPattern.exec(apkName)) {
+            if (archPattern.exec(apkName)) {
+                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('../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);
+};

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/builders/AntBuilder.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/builders/AntBuilder.js b/bin/templates/cordova/lib/builders/AntBuilder.js
index dd47227..d214f48 100644
--- a/bin/templates/cordova/lib/builders/AntBuilder.js
+++ b/bin/templates/cordova/lib/builders/AntBuilder.js
@@ -1,141 +1,141 @@
-/*
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
-*/
-
-var Q = require('q');
-var fs = require('fs');
-var path = require('path');
-var util = require('util');
-var shell = require('shelljs');
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-var check_reqs = require('../check_reqs');
-
-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';
-
-var GenericBuilder = require('./GenericBuilder');
-
-function AntBuilder (projectRoot) {
-    GenericBuilder.call(this, projectRoot);
-
-    this.binDirs = {ant: this.binDirs.ant};
-}
-
-util.inherits(AntBuilder, GenericBuilder);
-
-AntBuilder.prototype.getArgs = function(cmd, opts) {
-    var args = [cmd, '-f', path.join(this.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(this.root, opts.buildType + SIGNING_PROPERTIES));
-    }
-    return args;
-};
-
-AntBuilder.prototype.prepEnv = function(opts) {
-    var self = this;
-    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.
-        /*jshint -W069 */
-        var sdkDir = process.env['ANDROID_HOME'];
-        /*jshint +W069 */
-        var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
-        function writeBuildXml(projectPath) {
-            var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
-            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(self.root);
-        var propertiesObj = self.readProjectProperties();
-        var subProjects = propertiesObj.libs;
-        for (var i = 0; i < subProjects.length; ++i) {
-            writeBuildXml(path.join(self.root, subProjects[i]));
-        }
-        if (propertiesObj.systemLibs.length > 0) {
-            throw new CordovaError('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(self.root, propertiesFile);
-        if (opts.packageInfo) {
-            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
-        } else if(isAutoGenerated(propertiesFilePath)) {
-            shell.rm('-f', propertiesFilePath);
-        }
-    });
-};
-
-/*
- * Builds the project with ant.
- * Returns a promise.
- */
-AntBuilder.prototype.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() {
-        return spawn('ant', args, {stdio: 'inherit'});
-    });
-};
-
-AntBuilder.prototype.clean = function(opts) {
-    var args = this.getArgs('clean', opts);
-    var self = this;
-    return check_reqs.check_ant()
-    .then(function() {
-        return spawn('ant', args, {stdio: 'inherit'});
-    })
-    .then(function () {
-        shell.rm('-rf', path.join(self.root, 'out'));
-
-        ['debug', 'release'].forEach(function(config) {
-            var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
-            if(isAutoGenerated(propertiesFilePath)){
-                shell.rm('-f', propertiesFilePath);
-            }
-        });
-    });
-};
-
-module.exports = AntBuilder;
-
-function hasCustomRules(projectRoot) {
-    return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
-}
-
-function isAutoGenerated(file) {
-    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
-}
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var shell = require('shelljs');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var check_reqs = require('../check_reqs');
+
+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';
+
+var GenericBuilder = require('./GenericBuilder');
+
+function AntBuilder (projectRoot) {
+    GenericBuilder.call(this, projectRoot);
+
+    this.binDirs = {ant: this.binDirs.ant};
+}
+
+util.inherits(AntBuilder, GenericBuilder);
+
+AntBuilder.prototype.getArgs = function(cmd, opts) {
+    var args = [cmd, '-f', path.join(this.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(this.root, opts.buildType + SIGNING_PROPERTIES));
+    }
+    return args;
+};
+
+AntBuilder.prototype.prepEnv = function(opts) {
+    var self = this;
+    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.
+        /*jshint -W069 */
+        var sdkDir = process.env['ANDROID_HOME'];
+        /*jshint +W069 */
+        var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
+        function writeBuildXml(projectPath) {
+            var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
+            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(self.root);
+        var propertiesObj = self.readProjectProperties();
+        var subProjects = propertiesObj.libs;
+        for (var i = 0; i < subProjects.length; ++i) {
+            writeBuildXml(path.join(self.root, subProjects[i]));
+        }
+        if (propertiesObj.systemLibs.length > 0) {
+            throw new CordovaError('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(self.root, propertiesFile);
+        if (opts.packageInfo) {
+            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+        } else if(isAutoGenerated(propertiesFilePath)) {
+            shell.rm('-f', propertiesFilePath);
+        }
+    });
+};
+
+/*
+ * Builds the project with ant.
+ * Returns a promise.
+ */
+AntBuilder.prototype.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() {
+        return spawn('ant', args, {stdio: 'inherit'});
+    });
+};
+
+AntBuilder.prototype.clean = function(opts) {
+    var args = this.getArgs('clean', opts);
+    var self = this;
+    return check_reqs.check_ant()
+    .then(function() {
+        return spawn('ant', args, {stdio: 'inherit'});
+    })
+    .then(function () {
+        shell.rm('-rf', path.join(self.root, 'out'));
+
+        ['debug', 'release'].forEach(function(config) {
+            var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
+            if(isAutoGenerated(propertiesFilePath)){
+                shell.rm('-f', propertiesFilePath);
+            }
+        });
+    });
+};
+
+module.exports = AntBuilder;
+
+function hasCustomRules(projectRoot) {
+    return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
+}
+
+function isAutoGenerated(file) {
+    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/builders/GradleBuilder.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/builders/GradleBuilder.js b/bin/templates/cordova/lib/builders/GradleBuilder.js
index 7611423..0f613cc 100644
--- a/bin/templates/cordova/lib/builders/GradleBuilder.js
+++ b/bin/templates/cordova/lib/builders/GradleBuilder.js
@@ -1,213 +1,213 @@
-/*
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
-*/
-
-var Q = require('q');
-var fs = require('fs');
-var util = require('util');
-var path = require('path');
-var shell = require('shelljs');
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-var check_reqs = require('../check_reqs');
-
-var GenericBuilder = require('./GenericBuilder');
-
-var MARKER = 'YOUR CHANGES WILL BE ERASED!';
-var SIGNING_PROPERTIES = '-signing.properties';
-var TEMPLATE =
-    '# This file is automatically generated.\n' +
-    '# Do not modify this file -- ' + MARKER + '\n';
-
-function GradleBuilder (projectRoot) {
-    GenericBuilder.call(this, projectRoot);
-
-    this.binDirs = {gradle: this.binDirs.gradle};
-}
-
-util.inherits(GradleBuilder, GenericBuilder);
-
-GradleBuilder.prototype.getArgs = function(cmd, opts) {
-    if (cmd == 'release') {
-        cmd = 'cdvBuildRelease';
-    } else if (cmd == 'debug') {
-        cmd = 'cdvBuildDebug';
-    }
-    var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
-    if (opts.arch) {
-        args.push('-PcdvBuildArch=' + opts.arch);
-    }
-
-    // 10 seconds -> 6 seconds
-    args.push('-Dorg.gradle.daemon=true');
-    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.
-GradleBuilder.prototype.prepBuildFiles = function() {
-    // Update the version of build.gradle in each dependent library.
-    var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
-    var propertiesObj = this.readProjectProperties();
-    var subProjects = propertiesObj.libs;
-    for (var i = 0; i < subProjects.length; ++i) {
-        if (subProjects[i] !== 'CordovaLib') {
-            shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
-        }
-    }
-
-    var name = this.extractRealProjectNameFromManifest();
-    //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
-    var settingsGradlePaths =  subProjects.map(function(p){
-        var realDir=p.replace(/[/\\]/g, ':');
-        var libName=realDir.replace(name+'-','');
-        var str='include ":'+libName+'"\n';
-        if(realDir.indexOf(name+'-')!==-1)
-            str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
-        return str;
-    });
-
-    // Write the settings.gradle file.
-    fs.writeFileSync(path.join(this.root, 'settings.gradle'),
-        '// GENERATED FILE - DO NOT EDIT\n' +
-        'include ":"\n' + settingsGradlePaths.join(''));
-    // Update dependencies within build.gradle.
-    var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
-    var depsList = '';
-    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 CordovaError('Unsupported system library (does not work with gradle): ' + p);
-            }
-        }
-        depsList += '    compile "' + mavenRef + '"\n';
-    });
-    buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + '    $2');
-    var includeList = '';
-    propertiesObj.gradleIncludes.forEach(function(includePath) {
-        includeList += 'apply from: "' + includePath + '"\n';
-    });
-    buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
-    fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
-};
-
-GradleBuilder.prototype.prepEnv = function(opts) {
-    var self = this;
-    return check_reqs.check_gradle()
-    .then(function() {
-        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.
-        // check_reqs ensures that this is set.
-        /*jshint -W069 */
-        var sdkDir = process.env['ANDROID_HOME'];
-        /*jshint +W069 */
-        var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
-        if (process.platform == 'win32') {
-            shell.rm('-f', path.join(self.root, 'gradlew.bat'));
-            shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
-        } else {
-            shell.rm('-f', path.join(self.root, 'gradlew'));
-            shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
-        }
-        shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
-        shell.mkdir('-p', path.join(self.root, 'gradle'));
-        shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
-
-        // If the gradle distribution URL is set, make sure it points to version we want.
-        // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
-        // For some reason, using ^ and $ don't work.  This does the job, though.
-        var distributionUrlRegex = /distributionUrl.*zip/;
-        /*jshint -W069 */
-        var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
-        /*jshint +W069 */
-        var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
-        shell.chmod('u+w', gradleWrapperPropertiesPath);
-        shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
-
-        var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
-        var propertiesFilePath = path.join(self.root, propertiesFile);
-        if (opts.packageInfo) {
-            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
-        } else if (isAutoGenerated(propertiesFilePath)) {
-            shell.rm('-f', propertiesFilePath);
-        }
-    });
-};
-
-/*
- * Builds the project with gradle.
- * Returns a promise.
- */
-GradleBuilder.prototype.build = function(opts) {
-    var wrapper = path.join(this.root, 'gradlew');
-    var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
-    return Q().then(function() {
-        return spawn(wrapper, args, {stdio: 'inherit'});
-    });
-};
-
-GradleBuilder.prototype.clean = function(opts) {
-    var builder = this;
-    var wrapper = path.join(this.root, 'gradlew');
-    var args = builder.getArgs('clean', opts);
-    return Q().then(function() {
-        return spawn(wrapper, args, {stdio: 'inherit'});
-    })
-    .then(function () {
-        shell.rm('-rf', path.join(builder.root, 'out'));
-
-        ['debug', 'release'].forEach(function(config) {
-            var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
-            if(isAutoGenerated(propertiesFilePath)){
-                shell.rm('-f', propertiesFilePath);
-            }
-        });
-    });
-};
-
-module.exports = GradleBuilder;
-
-function isAutoGenerated(file) {
-    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
-}
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var util = require('util');
+var path = require('path');
+var shell = require('shelljs');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var check_reqs = require('../check_reqs');
+
+var GenericBuilder = require('./GenericBuilder');
+
+var MARKER = 'YOUR CHANGES WILL BE ERASED!';
+var SIGNING_PROPERTIES = '-signing.properties';
+var TEMPLATE =
+    '# This file is automatically generated.\n' +
+    '# Do not modify this file -- ' + MARKER + '\n';
+
+function GradleBuilder (projectRoot) {
+    GenericBuilder.call(this, projectRoot);
+
+    this.binDirs = {gradle: this.binDirs.gradle};
+}
+
+util.inherits(GradleBuilder, GenericBuilder);
+
+GradleBuilder.prototype.getArgs = function(cmd, opts) {
+    if (cmd == 'release') {
+        cmd = 'cdvBuildRelease';
+    } else if (cmd == 'debug') {
+        cmd = 'cdvBuildDebug';
+    }
+    var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
+    if (opts.arch) {
+        args.push('-PcdvBuildArch=' + opts.arch);
+    }
+
+    // 10 seconds -> 6 seconds
+    args.push('-Dorg.gradle.daemon=true');
+    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.
+GradleBuilder.prototype.prepBuildFiles = function() {
+    // Update the version of build.gradle in each dependent library.
+    var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
+    var propertiesObj = this.readProjectProperties();
+    var subProjects = propertiesObj.libs;
+    for (var i = 0; i < subProjects.length; ++i) {
+        if (subProjects[i] !== 'CordovaLib') {
+            shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
+        }
+    }
+
+    var name = this.extractRealProjectNameFromManifest();
+    //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
+    var settingsGradlePaths =  subProjects.map(function(p){
+        var realDir=p.replace(/[/\\]/g, ':');
+        var libName=realDir.replace(name+'-','');
+        var str='include ":'+libName+'"\n';
+        if(realDir.indexOf(name+'-')!==-1)
+            str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
+        return str;
+    });
+
+    // Write the settings.gradle file.
+    fs.writeFileSync(path.join(this.root, 'settings.gradle'),
+        '// GENERATED FILE - DO NOT EDIT\n' +
+        'include ":"\n' + settingsGradlePaths.join(''));
+    // Update dependencies within build.gradle.
+    var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
+    var depsList = '';
+    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 CordovaError('Unsupported system library (does not work with gradle): ' + p);
+            }
+        }
+        depsList += '    compile "' + mavenRef + '"\n';
+    });
+    buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + '    $2');
+    var includeList = '';
+    propertiesObj.gradleIncludes.forEach(function(includePath) {
+        includeList += 'apply from: "' + includePath + '"\n';
+    });
+    buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
+    fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
+};
+
+GradleBuilder.prototype.prepEnv = function(opts) {
+    var self = this;
+    return check_reqs.check_gradle()
+    .then(function() {
+        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.
+        // check_reqs ensures that this is set.
+        /*jshint -W069 */
+        var sdkDir = process.env['ANDROID_HOME'];
+        /*jshint +W069 */
+        var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
+        if (process.platform == 'win32') {
+            shell.rm('-f', path.join(self.root, 'gradlew.bat'));
+            shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
+        } else {
+            shell.rm('-f', path.join(self.root, 'gradlew'));
+            shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
+        }
+        shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
+        shell.mkdir('-p', path.join(self.root, 'gradle'));
+        shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
+
+        // If the gradle distribution URL is set, make sure it points to version we want.
+        // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
+        // For some reason, using ^ and $ don't work.  This does the job, though.
+        var distributionUrlRegex = /distributionUrl.*zip/;
+        /*jshint -W069 */
+        var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
+        /*jshint +W069 */
+        var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
+        shell.chmod('u+w', gradleWrapperPropertiesPath);
+        shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
+
+        var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+        var propertiesFilePath = path.join(self.root, propertiesFile);
+        if (opts.packageInfo) {
+            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+        } else if (isAutoGenerated(propertiesFilePath)) {
+            shell.rm('-f', propertiesFilePath);
+        }
+    });
+};
+
+/*
+ * Builds the project with gradle.
+ * Returns a promise.
+ */
+GradleBuilder.prototype.build = function(opts) {
+    var wrapper = path.join(this.root, 'gradlew');
+    var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
+    return Q().then(function() {
+        return spawn(wrapper, args, {stdio: 'inherit'});
+    });
+};
+
+GradleBuilder.prototype.clean = function(opts) {
+    var builder = this;
+    var wrapper = path.join(this.root, 'gradlew');
+    var args = builder.getArgs('clean', opts);
+    return Q().then(function() {
+        return spawn(wrapper, args, {stdio: 'inherit'});
+    })
+    .then(function () {
+        shell.rm('-rf', path.join(builder.root, 'out'));
+
+        ['debug', 'release'].forEach(function(config) {
+            var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
+            if(isAutoGenerated(propertiesFilePath)){
+                shell.rm('-f', propertiesFilePath);
+            }
+        });
+    });
+};
+
+module.exports = GradleBuilder;
+
+function isAutoGenerated(file) {
+    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/0ac822c5/bin/templates/cordova/lib/device.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/device.js b/bin/templates/cordova/lib/device.js
index 5dd79b5..e62e3db 100644
--- a/bin/templates/cordova/lib/device.js
+++ b/bin/templates/cordova/lib/device.js
@@ -1,106 +1,106 @@
-#!/usr/bin/env node
-
-/*
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
-*/
-
-var Q     = require('q'),
-    build = require('./build');
-var path = require('path');
-var Adb = require('./Adb');
-var AndroidManifest = require('./AndroidManifest');
-var spawn = require('cordova-common').superspawn.spawn;
-var CordovaError = require('cordova-common').CordovaError;
-var events = require('cordova-common').events;
-
-/**
- * Returns a promise for the list of the device ID's found
- * @param lookHarder When true, try restarting adb if no devices are found.
- */
-module.exports.list = function(lookHarder) {
-    return Adb.devices()
-    .then(function(list) {
-        if (list.length === 0 && lookHarder) {
-            // adb kill-server doesn't seem to do the trick.
-            // Could probably find a x-platform version of killall, but I'm not actually
-            // sure that this scenario even happens on non-OSX machines.
-            return spawn('killall', ['adb'])
-            .then(function() {
-                events.emit('verbose', 'Restarting adb to see if more devices are detected.');
-                return Adb.devices();
-            }, function() {
-                // For non-killall OS's.
-                return list;
-            });
-        }
-        return list;
-    });
-};
-
-module.exports.resolveTarget = function(target) {
-    return this.list(true)
-    .then(function(device_list) {
-        if (!device_list || !device_list.length) {
-            return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
-        }
-        // default device
-        target = target || device_list[0];
-
-        if (device_list.indexOf(target) < 0) {
-            return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
-        }
-
-        return build.detectArchitecture(target)
-        .then(function(arch) {
-            return { target: target, arch: arch, isEmulator: false };
-        });
-    });
-};
-
-/*
- * Installs a previously built application on the device
- * and launches it.
- * Returns a promise.
- */
-module.exports.install = function(target, buildResults) {
-    return Q().then(function() {
-        if (target && typeof target == 'object') {
-            return target;
-        }
-        return module.exports.resolveTarget(target);
-    }).then(function(resolvedTarget) {
-        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
-        var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
-        var pkgName = manifest.getPackageId();
-        var launchName = pkgName + '/.' + manifest.getActivity().getName();
-        events.emit('log', 'Using apk: ' + apk_path);
-        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
-        // or the app doesn't installed at all, so no error catching needed.
-        return Adb.uninstall(resolvedTarget.target, pkgName)
-        .then(function() {
-            return Adb.install(resolvedTarget.target, apk_path, {replace: true});
-        }).then(function() {
-            //unlock screen
-            return Adb.shell(resolvedTarget.target, 'input keyevent 82');
-        }).then(function() {
-            return Adb.start(resolvedTarget.target, launchName);
-        }).then(function() {
-            events.emit('log', 'LAUNCH SUCCESS');
-        });
-    });
-};
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var Q     = require('q'),
+    build = require('./build');
+var path = require('path');
+var Adb = require('./Adb');
+var AndroidManifest = require('./AndroidManifest');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var events = require('cordova-common').events;
+
+/**
+ * Returns a promise for the list of the device ID's found
+ * @param lookHarder When true, try restarting adb if no devices are found.
+ */
+module.exports.list = function(lookHarder) {
+    return Adb.devices()
+    .then(function(list) {
+        if (list.length === 0 && lookHarder) {
+            // adb kill-server doesn't seem to do the trick.
+            // Could probably find a x-platform version of killall, but I'm not actually
+            // sure that this scenario even happens on non-OSX machines.
+            return spawn('killall', ['adb'])
+            .then(function() {
+                events.emit('verbose', 'Restarting adb to see if more devices are detected.');
+                return Adb.devices();
+            }, function() {
+                // For non-killall OS's.
+                return list;
+            });
+        }
+        return list;
+    });
+};
+
+module.exports.resolveTarget = function(target) {
+    return this.list(true)
+    .then(function(device_list) {
+        if (!device_list || !device_list.length) {
+            return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
+        }
+        // default device
+        target = target || device_list[0];
+
+        if (device_list.indexOf(target) < 0) {
+            return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
+        }
+
+        return build.detectArchitecture(target)
+        .then(function(arch) {
+            return { target: target, arch: arch, isEmulator: false };
+        });
+    });
+};
+
+/*
+ * Installs a previously built application on the device
+ * and launches it.
+ * Returns a promise.
+ */
+module.exports.install = function(target, buildResults) {
+    return Q().then(function() {
+        if (target && typeof target == 'object') {
+            return target;
+        }
+        return module.exports.resolveTarget(target);
+    }).then(function(resolvedTarget) {
+        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
+        var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
+        var pkgName = manifest.getPackageId();
+        var launchName = pkgName + '/.' + manifest.getActivity().getName();
+        events.emit('log', 'Using apk: ' + apk_path);
+        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
+        // or the app doesn't installed at all, so no error catching needed.
+        return Adb.uninstall(resolvedTarget.target, pkgName)
+        .then(function() {
+            return Adb.install(resolvedTarget.target, apk_path, {replace: true});
+        }).then(function() {
+            //unlock screen
+            return Adb.shell(resolvedTarget.target, 'input keyevent 82');
+        }).then(function() {
+            return Adb.start(resolvedTarget.target, launchName);
+        }).then(function() {
+            events.emit('log', 'LAUNCH SUCCESS');
+        });
+    });
+};


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org