Compare commits

..

50 Commits

Author SHA1 Message Date
Andrew Grieve
52e575e1e7 Update .gitignore to ignore /framework/build and /node_modules 2014-10-04 15:14:45 -04:00
Martin Gonzalez
890e12c306 CB-6837 Fix leaked window when hitting back button while alert being rendered
Keep track of the last AlertDialog showed.
The last dialog showed that is rendered while hitting back button it
causes a leaked window.
Instead of perform a full track of all dialogs created, only destroy the
last one showed, this fixes the problem.

close #122
2014-10-04 14:44:06 -04:00
Joe Bowser
6cbf6b7875 CB-7674: Added sleep to avoid null error after most recent change to not break API 2014-09-30 17:57:42 -07:00
Marcel Kinard
c255a84941 CB-7674 move preference activation back into onCreate()
The preference creation actually needs to be before
super.onCreate(savedInstance) in order to avoid the exception
"requestFeature() must be called before adding content". Also ran into an
issue in the native tests "Whitelist" and "User WebView/Client/Chrome" where
it would throw an exception that the CordovaWebView appView already had
a parent and needed to be removed from that parent before the invocation
to root.addView(appView). So I conditionally remove the wrong parent.
Also made a change to the native tests so the menus test would work.
I also put super.init() back into the template, though invoking it is optional
as loadUrl will call it automatically if needed.
2014-09-30 19:38:34 -04:00
Steven Gill
ce7d6d69d9 updated release notes 2014-09-30 13:10:16 -07:00
Steven Gill
d5538b7076 updated .gitignore to include npm-debug.log 2014-09-29 23:49:12 -07:00
Steven Gill
cdfa13b265 Update JS snapshot to version 3.7.0-dev (via coho) 2014-09-29 14:59:07 -07:00
Andrew Grieve
e31c911c30 CB-7634 Detect JAVA_HOME properly on Ubuntu 2014-09-29 10:16:22 -04:00
Marcel Kinard
a658ea1573 CB-7410 update the docs to match the actual title 2014-09-25 11:25:09 -04:00
Max Woghiren
a986e72338 Added gradle distribution URL updating. (commit fix-up) 2014-09-24 16:18:18 -04:00
Andrew Grieve
162d9b6c2e gradle: Build only the active architecture when applicable 2014-09-24 16:16:59 -04:00
Andrew Grieve
9e3ccf4b3e gradle: Fix warning about dynamic properties being deprecated 2014-09-23 21:04:04 -04:00
Andrew Grieve
6b71c2f392 gradle: Have project's build.gradle look for a build-extras.gradle 2014-09-23 21:03:17 -04:00
Andrew Grieve
0d313a3964 gradle: Write sub-project list explicitly to make Android Studio happy 2014-09-23 21:03:00 -04:00
Max Woghiren
ddac192c4a Added gradle distribution URL updating.
Conflicts:
	bin/templates/cordova/lib/build.js
	framework/build.gradle
2014-09-22 22:27:43 -04:00
Andrew Grieve
69a03c2e16 CB-7512 Use a standard build.gradle for all plugins
Plugins can extend it by providing a "build-extras.gradle"
2014-09-22 22:27:43 -04:00
Andrew Grieve
2b128b85f7 CB-7512 Make gradle build only a single config for sub-libraries (release vs debug) 2014-09-22 20:54:28 -04:00
Andrew Grieve
879da03438 CB-7579 Fix run script's ability to use non-arch-specific APKs 2014-09-22 14:23:30 -04:00
Andrew Grieve
3f83fdbfc1 CB-7512 Fix gradle asking for release password when building for debug 2014-09-17 21:27:06 -04:00
purplecabbage
949152532c Merge branch 'CB-7493' of https://github.com/MSOpenTech/cordova-android 2014-09-17 14:58:08 -07:00
Ian Clelland
7ce46ed60c CB-3445: Make minSdkVersion and base versionCode settable through env vars 2014-09-17 15:58:22 -04:00
Andrew Grieve
cb442364ca CB-7512 Make key password optional & prompt for it when missing 2014-09-17 15:29:57 -04:00
Andrew Grieve
ac34bf1e54 CB-7512 Fix gradle not copying all archs to out/ (broken by prev commit) 2014-09-16 15:14:40 -04:00
Andrew Grieve
a5d300c6ff CB-7512 Use aligned apk rather than unaligned apk when sorting 2014-09-16 14:59:43 -04:00
Andrew Grieve
533677df8b CB-7512 Speed up gradle builds by building debug or release (not both) 2014-09-16 14:13:49 -04:00
Andrew Grieve
25be42d385 CB-7512 Add gradle environment vars for signing apks 2014-09-16 13:01:25 -04:00
Andrew Grieve
00f6d30e08 CB-7512 Change gradle android plugins from 0.10 -> 0.12 2014-09-16 13:00:27 -04:00
Andrew Grieve
090822eb41 CB-7536 check_reqs: windows tweaks + sdk manager error message
1. Don't escape \s since those are used by windows for directory seperators
2. Don't warn about missing directories on windows when we're just
testing for their existence
3. Don't give command to install sdk from command-line, since they also
require Build-tools and Platform-tools (which are not installed by
default with IDE-less SDK installer).
2014-09-16 11:13:15 -04:00
mbillau
d9900a725d Second part of CB-7499, support RTL text direction 2014-09-15 16:03:00 -04:00
Andrew Grieve
5cb01f2ae9 CB-7554 Use x86 apk when deploying to an intel device / emulator 2014-09-15 14:23:26 -04:00
Ian Clelland
4be92f285a CB-7512: Fix logic for detecting SDK directory 2014-09-15 12:15:32 -04:00
Michal Mocny
f9b89e98c2 Fix invalid syntax (missing + in multiline string) 2014-09-15 10:34:43 -04:00
Marcel Kinard
f221441877 Update JS snapshot to version 3.7.0-dev (via coho) 2014-09-12 16:34:06 -04:00
Andrew Grieve
f2e8c00f49 CB-7536 Tweak Android SDK not installed error message.
We no longer require you to edit your PATH
2014-09-12 16:17:42 -04:00
Andrew Grieve
525ce0e0ad CB-7536 Tweak error messages for missing JDK / SDK / AVDs 2014-09-12 14:19:13 -04:00
Andrew Grieve
2f7ffa3636 CB-7511 Auto-detect android sdk when using stand-alone sdk installer 2014-09-11 15:37:22 -04:00
Ian Clelland
9ae3d2c074 CB-7512: Copy cordova.gradle file to project root on build 2014-09-11 15:12:07 -04:00
Andrew Grieve
bf13fd48ce Use add --compact flag in check_reqs when listing targets. No functional change. 2014-09-10 12:44:17 -04:00
Andrew Grieve
3b99760a42 CB-7330 Don't run check_reqs for bin/create.
The create / update script doesn't require any dependencies, so we
shouldn't fail without them.
2014-09-10 12:44:17 -04:00
Ian Clelland
0e78dc35d8 CB-7512: Read android target from project.properties if possible 2014-09-10 11:39:29 -04:00
Ian Clelland
c8bbdb23de CB-7512: Determine SDK and build tools version dynamcally at build time 2014-09-10 10:57:43 -04:00
Ian Clelland
7ee8117186 CB-7463: Adding licence to project template gradle file 2014-09-10 10:54:21 -04:00
Andrew Grieve
8237c41143 CB-7511 Auto-detect Android SDK when Android Studio is installed 2014-09-10 10:14:38 -04:00
Vladimir Kotikov
d52ca93ba6 CB-7493 Adds test-build command to package.json 2014-09-09 17:53:22 +04:00
Joe Bowser
8354651059 CB-7463: Looked at the Apache BigTop git, gradle uses C-style comments 2014-09-04 10:49:43 -07:00
Joe Bowser
81cc3c260f CB-7463: Adding licences. I don't know what the gradle syntax is for comments, that still needs to be done. 2014-09-04 10:32:29 -07:00
Joe Bowser
4dc32e194b CB-7460: Fixing bug with KitKat where the background colour would override the CSS colours on the application 2014-09-03 15:42:39 -07:00
Steven Gill
5a82dd5110 updated releasenotes 2014-09-02 17:09:24 -07:00
Steven Gill
f20708a5e7 Update JS snapshot to version 3.7.0-dev (via coho) 2014-08-29 16:34:17 -07:00
Steven Gill
91cf78f183 Set VERSION to 3.7.0-dev (via coho) 2014-08-29 16:34:12 -07:00
27 changed files with 938 additions and 345 deletions

3
.gitignore vendored
View File

@@ -37,3 +37,6 @@ Desktop.ini
# IntelliJ IDEA files
*.iml
.idea
npm-debug.log
/node_modules
/framework/build

5
.travis.yml Normal file
View File

@@ -0,0 +1,5 @@
language: android
install: npm install
script:
- npm test
- npm run test-build

View File

@@ -20,6 +20,135 @@
-->
## Release Notes for Cordova (Android) ##
### 3.6.4 (Sept 30, 2014) ###
* Set VERSION to 3.6.4 (via coho)
* Update JS snapshot to version 3.6.4 (via coho)
* CB-7634 Detect JAVA_HOME properly on Ubuntu
* CB-7579 Fix run script's ability to use non-arch-specific APKs
* CB-6511 Fixes build for android when app name contains unicode characters.
* CB-7463: Adding licences. I don't know what the gradle syntax is for comments, that still needs to be done.
* CB-7463: Looked at the Apache BigTop git, gradle uses C-style comments
* CB-7460: Fixing bug with KitKat where the background colour would override the CSS colours on the application
### 3.6.0 (Sept 2014) ###
* Set VERSION to 3.6.0 (via coho)
* CB-7410 fix the menu test
* CB-7410 Fix the errorUrl test
* CB-7410 Fix Basic Authentication test
* CB-3445: Allow build and run scripts to select APK by architecture
* CB-3445: Add environment variable 'BUILD_MULTIPLE_APKS' for splitting APKs based on architecture
* CB-3445: Ensure that JAR files in libs directory are included
* CB-7267 update RELEASENOTES for 3.5.1
* CB-7410 clarify the title
* CB-7385 update cordova.js for testing prior to branch/tag
* CB-7410 add whitelist entries to get iframe/GoogleMaps working
* CB-7291 propogate change in method signature to the native tests
* CB-7291: Restrict meaning of "\*" in internal whitelist to just http and https
* CB-7291: Only add file, content and data URLs to internal whitelist
* CB-7291: Add defaults to external whitelist
* CB-7291: Add external-launch-whitelist and use it for filtering intent launches
* CB-3445: Read project.properties to configure gradle libraries
* CB-7325 Fix error message in android_sdk_version.js when missing SDK on windows
* CB-7335 Add a .gitignore to android project template
* CB-7330 Fix dangling function call in last commit (broke gradle builds)
* CB-7330 Don't run "android update" during creation
* CB-3445 Add gradle support clean command (plus some code cleanup)
* CB-7044 Fix typo in prev commit causing check_reqs to always fail.
* CB-3445 Copy gradle wrapper in build instead of create
* CB-3445 Add .gradle template files for "update" as well as "create"
* CB-7044 Add JAVA_HOME when not set. Be stricter about ANDROID_HOME
* CB-3445 Speed up gradle building (incremental builds go from 10s -> 1.5s for me)
* CB-3445: android: Copy Gradle wrapper from Android SDK rather than bundling a JAR
* CB-3445: Add which to checked-in node_modules
* CB-3445: Add option to build and install with gradle
* CB-3445: Add an initial set of Gradle build scripts
* CB-7321 Don't require ant for create script
* CB-7044, CB-7299 Fix up PATH problems when possible.
* Change in test's AndroidManifest.xml needed for the test to run properly. Forgot the manifest.
* Change in test's AndroidManifest.xml needed for the test to run properly
* Adding tests related to 3.5.1
* CB-7261 Fix setNativeToJsBridgeMode sometimes crashing when switching to ONLINE_EVENT
* CB-7265 Fix crash when navigating to custom protocol (introduced in 3.5.1)
* Filter out non-launchable intents
* Handle unsupported protocol errors in webview better
* CB-7238: I should have collapsed this, but Config.init() must go before the creation of CordovaWebView
* CB-7238: Minor band-aid to get tests running again, this has to go away before 3.6.0 is released, since this is an API change.
* Extend whitelist to handle URLs without // chars
* CB-7172 Force window to have focus after resume
* CB-7159 Set background color of webView as well as its parent
* CB-7018 Fix setButtonPlumbedToJs never un-listening
* Undeprecate some just-deprecated symbols in PluginManager.
* @Deprecate methods of PluginManager that were never meant to be public
* Move plugin instantiation and instance storing logic PluginEntry->PluginManager
* Fix broken unit test due to missing Config.init() call
* Update to check for Google Glass APIs
* Fix for `android` not being in PATH check on Windows
* Displaying error when regex does not match.
* Fix broken compile due to previous commit :(
* Tweak CordovaPlugin.initialize method to be less deprecated.
* Un-deprecate CordovaActivity.init() - it's needed to tweak prefs in onCreate
* Tweak log messages in CordovaBridge with bridgeSecret is wrong
* Backport CordovaBridge from 4.0.x -> master
* Update unit tests to not use most deprecated things (e.g. DroidGap)
* Add non-String overloades for CordovaPreferences.set()
* Make CordovaWebview resilient to init() not being called (for backwards-compatibility)
* Add node_module licenses to LICENSE
* Update cordova.js snapshot to work with bridge changes
* Provide CordovaPlugin with CordovaPreferences. Add new Plugin.initialize()
* Convert usages of Config.\* to use the non-static versions
* Change getProperty -> prefs.get\* within CordovaActivity
* Make CordovaUriHelper class package-private
* Fix PluginManager.setPluginEntries not removing old entries
* Move registration of App plugin from config.xml -> code
* Make setWebViewClient an override instead of an overload. Delete Location-change JS->Native bridge mode (missed some of it).
* CB-4404 Revert setting android:windowSoftInputMode to "adjustPan"
* Refactor: Use ConfigXmlParser in activity. Adds CordovaWebView.init()
* Deprecate some convenience methods on CordovaActivity
* Fix CordovaPreferences not correctly parsing hex values (valueOf->decode)
* Refactor: Move url-filter information into PluginEntry.
* Don't re-parse config.xml in onResume.
* Move handling of Fullscreen preference to CordovaActivity
* Delete dead code from CordovaActivity
* Update .classpath to make Eclipse happy (just re-orders one line)
* Delete "CB-3064: The errorUrl is..." Log message left over from debugging presumably
* Refactor Config into ConfigXmlParser, CordovaPreferences
* Delete Location-change JS->Native bridge mode
* CB-5988 Allow exec() only from file: or start-up URL's domain
* CB-6761 Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly
* Update the errorurl to no longer use intents
* This breaks running the JUnit tests, we'll bring it back soon
* Refactoring the URI handling on Cordova, removing dead code
* CB-7018 Clean up and deprecation of some button-related functions
* CB-7017 Fix onload=true being set on all subsequent plugins
* CB-5971: Fix package / project validation
* CB-5971: Add unit tests to cordova-android
* CB-5971: Factor out package/project name validation logic
* Delete explicit activity.finish() in back button handling. No change in behaviour.
* CB-5971: This would have been a good first bug, too bad
* CB-4404: Changing where android:windowSoftInputMode is in the manifest so it works
* Add documentation referencing other implementation.
* CB-6851 Deprecate WebView.sendJavascript()
* CB-6876 Show the correct executable name
* CB-6876 Fix the "print usage"
* Trivial spelling fix in comments when reading CordovaResourceApi
* CB-6818: I want to remove this code, because Square didn't do their headers properly
* CB-6860 Add activity_name and launcher_name to AndroidManifest.xml & strings.xml
* Add a comment to custom_rules.xml saying why we move AndroidManifest.xml
* Remove +x from README.md
* CB-6784 Add missing licenses
* CB-6784 Add license to CONTRIBUTING.md
* Revert "defaults.xml: Add AndroidLaunchMode preference"
* updated RELEASENOTES
* CB-6315: Wrapping this so it runs on the UI thread
* CB-6723 Update package name for Robotium
* CB-6707 Update minSdkVersion to 10 consistently
* CB-5652 make visible cordova version
* Update JS snapshot to version 3.6.0-dev (via coho)
* Update JS snapshot to version 3.6.0-dev (via coho)
* Set VERSION to 3.6.0-dev (via coho)
### 3.5.1 (August 2014) ###
This was a security update to address CVE-2014-3500, CVE-2014-3501,

View File

@@ -1 +1 @@
3.6.0
3.7.0-dev

View File

@@ -48,20 +48,21 @@ function tryCommand(cmd, errMsg) {
// Get valid target from framework/project.properties
module.exports.get_target = function() {
if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
} else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
// if no target found, we're probably in a project and project.properties is in ROOT.
// this is called on the project itself, and can support Google APIs AND Vanilla Android
var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties')) ||
shelljs.grep(/target=Google Inc.:Google APIs:[\d+]/, path.join(ROOT, 'project.properties'));
if(target == "" || !target) {
// Try Google Glass APIs
target = shelljs.grep(/target=Google Inc.:Glass Development Kit Preview:[\d+]/, path.join(ROOT, 'project.properties'));
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].replace('\n', '').replace('\r', '');
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.
@@ -100,7 +101,8 @@ module.exports.check_java = function() {
});
} else {
// See if we can derive it from javac's location.
var maybeJavaHome = path.dirname(path.dirname(javacPath));
// fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
var maybeJavaHome = path.dirname(path.dirname(fs.realpathSync(javacPath)));
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
process.env['JAVA_HOME'] = maybeJavaHome;
} else {
@@ -109,10 +111,13 @@ module.exports.check_java = function() {
}
} 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);
@@ -125,13 +130,15 @@ module.exports.check_java = function() {
}
}).then(function() {
var msg =
'Failed to run "java -version", make sure your java environment is set up\n' +
'including JDK and JRE.\n' +
'Your JAVA_HOME variable is: ' + process.env['JAVA_HOME'];
'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() {
msg = 'Failed to run "javac -version", make sure you have a Java JDK (not just a JRE) installed.';
return tryCommand('javac -version', msg)
.then(function() {
return tryCommand('javac -version', msg);
});
});
}
@@ -141,6 +148,32 @@ module.exports.check_android = 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 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') {
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']) {
// or 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');
}
@@ -165,13 +198,27 @@ module.exports.check_android = function() {
});
};
module.exports.getAbsoluteAndroidCmd = function() {
return forgivingWhichSync('android').replace(/(\s)/g, '\\$1');
};
module.exports.check_android_target = function(valid_target) {
var msg = 'Failed to run "android". Make sure you have the latest Android SDK installed, and that the "android" command (inside the tools/ folder) is added to your PATH.';
return tryCommand('android list targets', msg)
// valid_target can look like:
// android-19
// android-L
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
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) {
if (!output.match(valid_target)) {
throw new Error('Please install Android target "' + valid_target + '".\n' +
'Hint: Run "android" from your command-line to open the SDK manager.');
if (output.split('\n').indexOf(valid_target) == -1) {
var androidCmd = module.exports.getAbsoluteAndroidCmd();
throw new Error('Please install Android target: "' + valid_target + '".\n\n' +
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
'You will require:\n' +
'1. "SDK Platform" for ' + valid_target + '\n' +
'2. "Android SDK Platform-tools (latest)\n' +
'3. "Android SDK Build-tools" (latest)');
}
});
};

View File

@@ -122,7 +122,7 @@ function copyBuildRules(projectPath) {
shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
shell.cp('-f', path.join(srcDir, 'settings.gradle'), projectPath);
shell.cp('-f', path.join(srcDir, 'cordova.gradle'), projectPath);
}
function copyScripts(projectPath) {
@@ -226,10 +226,6 @@ exports.createProject = function(project_path, package_name, project_name, proje
return validatePackageName(package_name)
.then(function() {
validateProjectName(project_name);
})
// Check that requirements are met and proper targets are installed
.then(function() {
return check_reqs.run();
}).then(function() {
// Log the given values for the project
console.log('Creating Cordova project for the Android platform:');
@@ -305,8 +301,7 @@ function extractProjectNameFromManifest(projectPath) {
// Returns a promise.
exports.updateProject = function(projectPath, shared) {
var newVersion = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
// Check that requirements are met and proper targets are installed
return check_reqs.run()
return Q()
.then(function() {
var projectName = extractProjectNameFromManifest(projectPath);
var target_api = check_reqs.get_target();

View File

@@ -26,25 +26,58 @@ var shell = require('shelljs'),
fs = require('fs'),
ROOT = path.join(__dirname, '..', '..');
var check_reqs = require('./check_reqs');
var exec = require('./exec');
var LOCAL_PROPERTIES_TEMPLATE =
'# This file is automatically generated.\n' +
'# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n';
function find_files(directory, predicate) {
function findApks(directory) {
var ret = [];
if (fs.existsSync(directory)) {
var candidates = fs.readdirSync(directory).filter(predicate).map(function(p) {
p = path.join(directory, p);
return { p: p, t: fs.statSync(p).mtime };
}).sort(function(a,b) {
return a.t > b.t ? -1 :
a.t < b.t ? 1 : 0;
}).map(function(p) { return p.p; });
return candidates;
} else {
console.error('ERROR : unable to find project ' + directory + ' directory, could not locate .apk');
process.exit(2);
fs.readdirSync(directory).forEach(function(p) {
if (path.extname(p) == '.apk') {
ret.push(path.join(directory, p));
}
});
}
return ret;
}
function sortFilesByDate(files) {
return files.map(function(p) {
return { p: p, t: fs.statSync(p).mtime };
}).sort(function(a, b) {
var timeDiff = b.t - a.t;
return timeDiff === 0 ? a.p.length - b.p.length : timeDiff;
}).map(function(p) { return p.p; });
}
function findOutputApksHelper(dir, build_type, arch) {
var ret = findApks(dir).filter(function(candidate) {
// Need to choose between release and debug .apk.
if (build_type === 'debug') {
return /-debug/.exec(candidate) && !/-unaligned|-unsigned/.exec(candidate);
}
if (build_type === 'release') {
return /-release/.exec(candidate) && !/-unaligned/.exec(candidate);
}
return true;
});
ret = sortFilesByDate(ret);
if (ret.length === 0) {
return ret;
}
var archSpecific = !!/-x86|-arm/.exec(ret[0]);
ret = ret.filter(function(p) {
return !!/-x86|-arm/.exec(p) == archSpecific;
});
if (arch) {
ret = ret.filter(function(p) {
return p.indexOf('-' + arch) != -1;
});
}
return ret;
}
function hasCustomRules() {
@@ -123,8 +156,6 @@ var builders = {
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args);
}).then(function() {
return builder.getOutputFiles();
});
},
@@ -136,26 +167,13 @@ var builders = {
});
},
// Find the recently-generated output APK files
// Ant only generates one output file; return it.
getOutputFiles: function() {
var binDir;
if(hasCustomRules()) {
binDir = path.join(ROOT, 'ant-build');
} else {
binDir = path.join(ROOT, 'bin');
}
var candidates = find_files(binDir, function(candidate) { return path.extname(candidate) == '.apk'; });
if (candidates.length === 0) {
console.error('ERROR : No .apk found in ' + binDir + ' directory');
process.exit(2);
}
console.log('Using apk: ' + candidates[0]);
return [candidates[0]];
findOutputApks: function(build_type) {
var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin');
return findOutputApksHelper(binDir, build_type, null);
}
},
gradle: {
getArgs: function(cmd) {
getArgs: function(cmd, arch) {
var lintSteps;
if (process.env['BUILD_MULTIPLE_APKS']) {
lintSteps = [
@@ -175,6 +193,19 @@ var builders = {
'copyDebugLint'
];
}
if (arch == 'arm' && cmd == 'debug') {
cmd = 'assembleArmv7Debug';
} else if (arch == 'arm' && cmd == 'release') {
cmd = 'assembleArmv7Release';
} else if (arch == 'x86' && cmd == 'debug') {
cmd = 'assembleX86Debug';
} else if (arch == 'x86' && cmd == 'release') {
cmd = 'assembleX86Release';
} else if (cmd == 'debug') {
cmd = 'assembleDebug';
} else if (cmd == 'release') {
cmd = 'assembleRelease';
}
var args = [cmd, '-b', path.join(ROOT, 'build.gradle')];
// 10 seconds -> 6 seconds
args.push('-Dorg.gradle.daemon=true');
@@ -205,6 +236,36 @@ var builders = {
shell.rm('-rf', path.join(projectPath, 'gradle', 'wrapper'));
shell.mkdir('-p', path.join(projectPath, 'gradle'));
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(projectPath, 'gradle'));
// If the gradle distribution URL is set, make sure it points to version 1.12.
// 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.
var distributionUrlRegex = '/^distributionUrl=.*$/';
var distributionUrl = 'distributionUrl=http\\://services.gradle.org/distributions/gradle-1.12-all.zip';
var gradleWrapperPropertiesPath = path.join(projectPath, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.sed('-i', distributionUrlRegex, distributionUrl, gradleWrapperPropertiesPath);
// Update the version of build.gradle in each dependent library.
var pluginBuildGradle = path.join(projectPath, 'cordova', 'lib', 'plugin-build.gradle');
var subProjects = extractSubProjectPaths();
for (var i = 0; i < subProjects.length; ++i) {
shell.cp('-f', pluginBuildGradle, path.join(ROOT, subProjects[i], 'build.gradle'));
}
var subProjectsAsGradlePaths = subProjects.map(function(p) { return ':' + p.replace(/[/\\]/g, ':') });
// Write the settings.gradle file.
fs.writeFileSync(path.join(projectPath, 'settings.gradle'),
'// GENERATED FILE - DO NOT EDIT\n' +
'include ":"\n' +
'include "' + subProjectsAsGradlePaths.join('"\ninclude "') + '"\n');
// Update dependencies within build.gradle.
var buildGradle = fs.readFileSync(path.join(projectPath, 'build.gradle'), 'utf8');
var depsList = '';
subProjectsAsGradlePaths.forEach(function(p) {
depsList += ' debugCompile project(path: "' + p + '", configuration: "debug")\n';
depsList += ' releaseCompile project(path: "' + p + '", configuration: "release")\n';
});
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
fs.writeFileSync(path.join(projectPath, 'build.gradle'), buildGradle);
});
},
@@ -212,14 +273,12 @@ var builders = {
* Builds the project with gradle.
* Returns a promise.
*/
build: function(build_type) {
build: function(build_type, arch) {
var builder = this;
var wrapper = path.join(ROOT, 'gradlew');
var args = builder.getArgs('build');
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release', arch);
return Q().then(function() {
return spawn(wrapper, args);
}).then(function() {
return builder.getOutputFiles(build_type);
});
},
@@ -232,21 +291,9 @@ var builders = {
});
},
// Find the recently-generated output APK files
// Gradle can generate multiple output files; return all of them.
getOutputFiles: function(build_type) {
var binDir = path.join(ROOT, 'build', 'apk');
var candidates = find_files(binDir, function(candidate) {
// Need to choose between release and debug .apk.
if (build_type === 'debug') {
return (path.extname(candidate) == '.apk' && candidate.indexOf('-debug-') >= 0);
}
if (build_type === 'release') {
return (path.extname(candidate) == '.apk' && candidate.indexOf('-release-') >= 0);
}
return path.extname(candidate) == '.apk';
});
return candidates;
findOutputApks: function(build_type, arch) {
var binDir = path.join(ROOT, 'build', 'outputs', 'apk');
return findOutputApksHelper(binDir, build_type, arch);
}
},
@@ -256,26 +303,30 @@ var builders = {
},
build: function() {
console.log('Skipping build...');
return Q();
return Q(null);
},
clean: function() {
return Q();
},
findOutputApks: function(build_type, arch) {
return sortFilesByDate(builders.ant.findOutputApks(build_type, arch).concat(builders.gradle.findOutputApks(build_type, arch)));
}
}
};
function parseOpts(options) {
function parseOpts(options, resolvedTarget) {
// Backwards-compatibility: Allow a single string argument
if (typeof options == "string") options = [options];
var ret = {
buildType: 'debug',
buildMethod: process.env['ANDROID_BUILD'] || 'ant'
buildMethod: process.env['ANDROID_BUILD'] || 'ant',
arch: null
};
// Iterate through command line options
for (var i=0; options && (i < options.length); ++i) {
if (options[i].substring && options[i].substring(0,2) == "--") {
if (/^--/.exec(options[i])) {
var option = options[i].substring(2);
switch(option) {
case 'debug':
@@ -296,6 +347,12 @@ function parseOpts(options) {
return Q.reject('Build option \'' + options[i] + '\' not recognized.');
}
}
var multiApk = ret.buildMethod == 'gradle' && process.env['BUILD_MULTIPLE_APKS'];
if (multiApk && !/0|false|no/i.exec(multiApk)) {
ret.arch = resolvedTarget && resolvedTarget.arch;
}
return ret;
}
@@ -318,40 +375,57 @@ module.exports.runClean = function(options) {
* Builds the project with the specifed options
* Returns a promise.
*/
module.exports.run = function(options) {
var opts = parseOpts(options);
module.exports.run = function(options, optResolvedTarget) {
var opts = parseOpts(options, optResolvedTarget);
var builder = builders[opts.buildMethod];
return builder.prepEnv()
.then(function() {
return builder.build(opts.buildType);
}).then(function(apkFiles) {
// TODO: Rather than copy apks to out, it might be better to
// just write out what the last .apk build was. These files
// are used by get_apk().
var outputDir = path.join(ROOT, 'out');
shell.mkdir('-p', outputDir);
for (var i=0; i < apkFiles.length; ++i) {
shell.cp('-f', apkFiles[i], path.join(outputDir, path.basename(apkFiles[i])));
}
return builder.build(opts.buildType, opts.arch);
}).then(function() {
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
console.log('Built the following apk(s):');
console.log(' ' + apkPaths.join('\n '));
return {
apkPaths: apkPaths,
buildType: opts.buildType,
buildMethod: opts.buildMethod
};
});
};
/*
* Gets the path to the apk file, if not such file exists then
* the script will error out. (should we error or just return undefined?)
* This is called by the run script to install the apk to the device
* Detects the architecture of a device/emulator
* Returns "arm" or "x86".
*/
module.exports.get_apk = function(build_type, architecture) {
var outputDir = path.join(ROOT, 'out');
var candidates = find_files(outputDir, function(filename) { return (!architecture) || filename.indexOf(architecture) >= 0; });
if (candidates.length === 0) {
console.error('ERROR : No .apk found in ' + outputDir + ' directory');
process.exit(2);
module.exports.detectArchitecture = function(target) {
return exec('adb -s ' + target + ' shell cat /proc/cpuinfo')
.then(function(output) {
if (/intel/i.exec(output)) {
return 'x86';
}
return 'arm';
});
};
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
var paths = buildResults.apkPaths.filter(function(p) {
if (buildResults.buildType == 'debug') {
return /-debug/.exec(p);
}
return !/-debug/.exec(p);
});
var archPattern = new RegExp('-' + arch);
var hasArchPattern = /-x86|-arm/;
for (var i = 0; i < paths.length; ++i) {
if (hasArchPattern.exec(paths[i])) {
if (archPattern.exec(paths[i])) {
return paths[i];
}
} else {
return paths[i];
}
}
// TODO: Use build_type here.
console.log('Using apk: ' + candidates[0]);
return candidates[0];
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
};
module.exports.help = function() {

View File

@@ -43,49 +43,60 @@ module.exports.list = function() {
});
}
module.exports.resolveTarget = function(target) {
return this.list()
.then(function(device_list) {
if (!device_list || !device_list.length) {
return Q.reject('ERROR: Failed to deploy to device, no devices found.');
}
// default device
target = target || device_list[0];
if (device_list.indexOf(target) < 0) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
}
return build.detectArchitecture(target)
.then(function(arch) {
return { target: target, arch: arch, isEmulator: false };
});
});
};
/*
* Installs a previously built application on the device
* and launches it.
* Returns a promise.
*/
module.exports.install = function(target) {
var launchName;
return this.list()
.then(function(device_list) {
if (!device_list || !device_list.length)
return Q.reject('ERROR: Failed to deploy to device, no devices found.');
// default device
target = typeof target !== 'undefined' ? target : device_list[0];
if (device_list.indexOf(target) < 0)
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
var apk_path;
if (typeof process.env.DEPLOY_APK_ARCH == 'undefined') {
apk_path = build.get_apk();
} else {
apk_path = build.get_apk(null, process.env.DEPLOY_APK_ARCH);
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
launchName = appinfo.getActivityName();
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var launchName = appinfo.getActivityName();
console.log('Using apk: ' + apk_path);
console.log('Installing app on device...');
var cmd = 'adb -s ' + target + ' install -r "' + apk_path + '"';
return exec(cmd);
}).then(function(output) {
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
return exec(cmd)
.then(function(output) {
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
//unlock screen
var cmd = 'adb -s ' + target + ' shell input keyevent 82';
return exec(cmd);
}, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
.then(function() {
// launch the application
console.log('Launching application...');
var cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd);
}).then(function() {
console.log('LAUNCH SUCCESS');
}, function(err) {
return Q.reject('ERROR: Failed to launch application on device: ' + err);
//unlock screen
var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
return exec(cmd);
}, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
.then(function() {
// launch the application
console.log('Launching application...');
var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd);
}).then(function() {
console.log('LAUNCH SUCCESS');
}, function(err) {
return Q.reject('ERROR: Failed to launch application on device: ' + err);
});
});
}

View File

@@ -28,6 +28,7 @@ var shell = require('shelljs'),
ROOT = path.join(__dirname, '..', '..'),
child_process = require('child_process'),
new_emulator = 'cordova_emulator';
var check_reqs = require('./check_reqs');
/**
* Returns a Promise for a list of emulator images in the form of objects
@@ -84,7 +85,7 @@ module.exports.list_images = function() {
* Returns a promise.
*/
module.exports.best_image = function() {
var project_target = this.get_target().replace('android-', '');
var project_target = check_reqs.get_target().replace('android-', '');
return this.list_images()
.then(function(images) {
var closest = 9999;
@@ -120,11 +121,6 @@ module.exports.list_started = function() {
});
}
module.exports.get_target = function() {
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
}
// Returns a promise.
module.exports.list_targets = function() {
return exec('android list targets')
@@ -156,7 +152,7 @@ module.exports.start = function(emulator_ID) {
.then(function(list) {
started_emulators = list;
num_started = started_emulators.length;
if (typeof emulator_ID === 'undefined') {
if (!emulator_ID) {
return self.list_images()
.then(function(emulator_list) {
if (emulator_list.length > 0) {
@@ -167,11 +163,11 @@ module.exports.start = function(emulator_ID) {
return emulator_ID;
});
} else {
return Q.reject('ERROR : No emulator images (avds) found, if you would like to create an\n' +
' avd follow the instructions provided here:\n' +
' http://developer.android.com/tools/devices/index.html\n' +
' Or run \'android create avd --name <name> --target <targetID>\'\n' +
' in on the command line.');
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
return Q.reject('ERROR : No emulator images (avds) found.\n' +
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n');
}
});
} else {
@@ -277,14 +273,7 @@ module.exports.create_image = function(name, target) {
}
}
/*
* 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(target) {
var self = this;
module.exports.resolveTarget = function(target) {
return this.list_started()
.then(function(emulator_list) {
if (emulator_list.length < 1) {
@@ -292,33 +281,55 @@ module.exports.install = function(target) {
}
// default emulator
target = typeof target !== 'undefined' ? target : emulator_list[0];
target = target || emulator_list[0];
if (emulator_list.indexOf(target) < 0) {
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
}
console.log('Installing app on emulator...');
var apk_path = build.get_apk();
return exec('adb -s ' + target + ' install -r "' + apk_path + '"');
}).then(function(output) {
if (output.match(/Failure/)) {
return Q.reject('Failed to install apk to emulator: ' + output);
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(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
return Q();
}, function(err) {
return Q.reject('Failed to install apk to emulator: ' + err);
}).then(function() {
//unlock screen
return exec('adb -s ' + target + ' shell input keyevent 82');
}).then(function() {
// launch the application
console.log('Launching application...');
var launchName = appinfo.getActivityName();
cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd);
}).then(function(output) {
console.log('LAUNCH SUCCESS');
}, function(err) {
return Q.reject('Failed to launch app on emulator: ' + err);
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
console.log('Installing app on emulator...');
console.log('Using apk: ' + apk_path);
return exec('adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"')
.then(function(output) {
if (output.match(/Failure/)) {
return Q.reject('Failed to install apk to emulator: ' + output);
}
return Q();
}, function(err) {
return Q.reject('Failed to install apk to emulator: ' + err);
}).then(function() {
//unlock screen
return exec('adb -s ' + resolvedTarget.target + ' shell input keyevent 82');
}).then(function() {
// launch the application
console.log('Launching application...');
var launchName = appinfo.getActivityName();
cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd);
}).then(function(output) {
console.log('LAUNCH SUCCESS');
}, function(err) {
return Q.reject('Failed to launch app on emulator: ' + err);
});
});
}

View File

@@ -0,0 +1,63 @@
/* Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// GENERATED FILE! DO NOT EDIT!
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
}
}
apply plugin: 'android-library'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion cordova.cordovaSdkVersion
buildToolsVersion cordova.cordovaBuildToolsVersion
publishNonDefault true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
}
if (file('build-extras.gradle').exists()) {
apply from: 'build-extras.gradle'
}

View File

@@ -33,16 +33,16 @@ var path = require('path'),
* Returns a promise.
*/
module.exports.run = function(args) {
var build_type;
var buildFlags = [];
var install_target;
for (var i=2; i<args.length; i++) {
if (args[i] == '--debug') {
build_type = '--debug';
buildFlags.push('--debug');
} else if (args[i] == '--release') {
build_type = '--release';
buildFlags.push('--release');
} else if (args[i] == '--nobuild') {
build_type = '--nobuild';
buildFlags.push('--nobuild');
} else if (args[i] == '--device') {
install_target = '--device';
} else if (args[i] == '--emulator') {
@@ -55,73 +55,66 @@ var path = require('path'),
}
}
return build.run(build_type).then(function() {
if (install_target == '--device') {
return device.install();
} else if (install_target == '--emulator') {
return emulator.list_started().then(function(started) {
var p = started && started.length > 0 ? Q() : emulator.start();
return p.then(function() { emulator.install(); });
});
} else if (install_target) {
var devices, started_emulators, avds;
return device.list()
.then(function(res) {
devices = res;
return emulator.list_started();
}).then(function(res) {
started_emulators = res;
return emulator.list_images();
}).then(function(res) {
avds = res;
if (devices.indexOf(install_target) > -1) {
return device.install(install_target);
} else if (started_emulators.indexOf(install_target) > -1) {
return emulator.install(install_target);
} else {
// if target emulator isn't started, then start it.
var emulator_ID;
for(avd in avds) {
if(avds[avd].name == install_target) {
return emulator.start(install_target)
.then(function() { emulator.install(emulator_ID); });
}
}
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
}
});
} else {
return Q()
.then(function() {
if (!install_target) {
// no target given, deploy to device if available, otherwise use the emulator.
return device.list()
.then(function(device_list) {
if (device_list.length > 0) {
console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
return device.install(device_list[0]);
install_target = device_list[0];
} else {
return emulator.list_started()
.then(function(emulator_list) {
if (emulator_list.length > 0) {
console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.');
return emulator.install(emulator_list[0]);
} else {
console.log('WARNING : No started emulators found, starting an emulator.');
return emulator.best_image()
.then(function(best_avd) {
if(best_avd) {
return emulator.start(best_avd.name)
.then(function(emulator_ID) {
console.log('WARNING : No target specified, deploying to emulator \'' + emulator_ID + '\'.');
return emulator.install(emulator_ID);
});
} else {
return emulator.start();
}
});
}
});
console.log('WARNING : No target specified, deploying to emulator');
install_target = '--emulator';
}
});
}
}).then(function() {
if (install_target == '--device') {
return device.resolveTarget(null);
} else if (install_target == '--emulator') {
// Give preference to any already started emulators. Else, start one.
return emulator.list_started()
.then(function(started) {
return started && started.length > 0 ? started[0] : emulator.start();
}).then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
// They specified a specific device/emulator ID.
return device.list()
.then(function(devices) {
if (devices.indexOf(install_target) > -1) {
return device.resolveTarget(install_target);
}
return emulator.list_started()
.then(function(started_emulators) {
if (started_emulators.indexOf(install_target) > -1) {
return emulator.resolveTarget(install_target);
}
return emulator.list_images()
.then(function(avds) {
// if target emulator isn't started, then start it.
for (avd in avds) {
if (avds[avd].name == install_target) {
return emulator.start(install_target)
.then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
}
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
});
});
});
}).then(function(resolvedTarget) {
return build.run(buildFlags, resolvedTarget).then(function(buildResults) {
if (resolvedTarget.isEmulator) {
return emulator.install(resolvedTarget, buildResults);
}
return device.install(resolvedTarget, buildResults);
});
});
}

View File

@@ -20,6 +20,6 @@
*/
// Coho updates this line:
var VERSION = "3.6.0";
var VERSION = "3.7.0-dev";
console.log(VERSION);

View File

@@ -28,6 +28,7 @@ public class __ACTIVITY__ extends CordovaActivity
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
}

View File

@@ -31,7 +31,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:hardwareAccelerated="true">
android:hardwareAccelerated="true" android:supportsRtl="true">
<activity android:name="__ACTIVITY__"
android:label="@string/activity_name"
android:launchMode="singleTop"

View File

@@ -1,5 +1,29 @@
import java.util.regex.Pattern
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// GENERATED FILE! DO NOT EDIT!
import java.util.regex.Pattern
import groovy.swing.SwingBuilder
ext.cordova = {}
apply from: 'cordova.gradle', to: ext.cordova
apply plugin: 'android'
buildscript {
@@ -8,19 +32,16 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:0.10.+'
classpath 'com.android.tools.build:gradle:0.12.0+'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.12'
}
ext.multiarch=false
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
for (subproject in getProjectList()) {
compile project(subproject)
}
}
android {
sourceSets {
main {
@@ -35,11 +56,11 @@ android {
}
defaultConfig {
versionCode Integer.parseInt("" + getVersionCodeFromManifest() + "0")
versionCode Integer.parseInt(System.env.ANDROID_VERSION_CODE ?: ("" + getVersionCodeFromManifest() + "0"))
}
compileSdkVersion 19
buildToolsVersion "19.0.0"
compileSdkVersion cordova.cordovaSdkVersion
buildToolsVersion cordova.cordovaBuildToolsVersion
if (multiarch || System.env.BUILD_MULTIPLE_APKS) {
productFlavors {
@@ -68,10 +89,78 @@ android {
targetCompatibility JavaVersion.VERSION_1_7
}
if (System.env.RELEASE_SIGNING_PROPERTIES_FILE) {
signingConfigs {
release {
// These must be set or Gradle will complain (even if they are overridden).
keyAlias = ""
keyPassword = ""
storeFile = null
storePassword = ""
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
addSigningProps(System.env.RELEASE_SIGNING_PROPERTIES_FILE, signingConfigs.release)
}
if (System.env.DEBUG_SIGNING_PROPERTIES_FILE) {
addSigningProps(System.env.DEBUG_SIGNING_PROPERTIES_FILE, signingConfigs.debug)
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.12'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
// SUB-PROJECT DEPENDENCIES START
// SUB-PROJECT DEPENDENCIES END
}
def promptForPassword(msg) {
if (System.console() == null) {
def ret = null
new SwingBuilder().edt {
dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
vbox {
label(text: msg)
def input = passwordField()
button(defaultButton: true, text: 'OK', actionPerformed: {
ret = input.password;
dispose();
})
}
}
}
if (!ret) {
throw new GradleException('User canceled build')
}
return new String(ret)
} else {
return System.console().readPassword('\n' + msg);
}
}
def promptForReleaseKeyPassword() {
if (!System.env.RELEASE_SIGNING_PROPERTIES_FILE) {
return;
}
if (!android.signingConfigs.release.storePassword) {
android.signingConfigs.release.storePassword = promptForPassword('Enter key store password: ')
println('set to:' + android.signingConfigs.release.storePassword)
}
if (!android.signingConfigs.release.keyPassword) {
android.signingConfigs.release.keyPassword = promptForPassword('Enter key password: ');
}
}
gradle.taskGraph.whenReady { taskGraph ->
taskGraph.getAllTasks().each() { task ->
if (task.name == 'validateReleaseSigning') {
promptForReleaseKeyPassword()
}
}
}
def getVersionCodeFromManifest() {
@@ -82,13 +171,25 @@ def getVersionCodeFromManifest() {
return Integer.parseInt(matcher.group(1))
}
def getProjectList() {
def manifestFile = file("project.properties")
def pattern = Pattern.compile("android.library.reference.(\\d+)\\s*=\\s*(.*)")
def matcher = pattern.matcher(manifestFile.getText())
def projects = []
while (matcher.find()) {
projects.add(":" + matcher.group(2).replace("/",":"))
def ensureValueExists(filePath, props, key) {
if (props.get(key) == null) {
throw new GradleException(filePath + ': Missing key required "' + key + '"')
}
return projects
return props.get(key)
}
def addSigningProps(propsFilePath, signingConfig) {
def propsFile = file(propsFilePath)
propsFile.withReader { reader ->
def props = new Properties()
props.load(reader)
signingConfig.keyAlias = ensureValueExists(propsFilePath, props, 'keyAlias')
signingConfig.keyPassword = props.get('keyPassword')
signingConfig.storeFile = RelativePath.parse(true, ensureValueExists(propsFilePath, props, 'storeFile')).getFile(propsFile.getParentFile())
signingConfig.storePassword = props.get('storePassword')
}
}
if (file('build-extras.gradle').exists()) {
apply from: 'build-extras.gradle'
}

View File

@@ -0,0 +1,120 @@
/*
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.
*/
import java.util.regex.Pattern
String getProjectTarget(String defaultTarget) {
def manifestFile = file("project.properties")
def pattern = Pattern.compile("target\\s*=\\s*(.*)")
def matcher = pattern.matcher(manifestFile.getText())
if (matcher.find()) {
matcher.group(1)
} else {
defaultTarget
}
}
String[] getAvailableBuildTools() {
def buildToolsDir = new File(getAndroidSdkDir(), "build-tools")
buildToolsDir.list()
.findAll { it ==~ /[0-9.]+/ }
.sort { a, b -> compareVersions(b, a) }
}
String latestBuildToolsAvailable(String minBuildToolsVersion) {
def availableBuildToolsVersions
try {
availableBuildToolsVersions = getAvailableBuildTools()
} catch (e) {
println "An exception occurred while trying to find the Android build tools."
throw e
}
if (availableBuildToolsVersions.length > 0) {
def highestBuildToolsVersion = availableBuildToolsVersions[0]
if (compareVersions(highestBuildToolsVersion, minBuildToolsVersion) < 0) {
throw new RuntimeException(
"No usable Android build tools found. Highest installed version is " +
highestBuildToolsVersion + "; minimum version required is " +
minBuildToolsVersion + ".")
}
highestBuildToolsVersion
} else {
throw new RuntimeException(
"No installed build tools found. Please install the Android build tools version " +
minBuildToolsVersion + " or higher.")
}
}
// Return the first non-zero result of subtracting version list elements
// pairwise. If they are all identical, return the difference in length of
// the two lists.
int compareVersionList(Collection aParts, Collection bParts) {
def pairs = ([aParts, bParts]).transpose()
pairs.findResult(aParts.size()-bParts.size()) {it[0] - it[1] != 0 ? it[0] - it[1] : null}
}
// Compare two version strings, such as "19.0.0" and "18.1.1.0". If all matched
// elements are identical, the longer version is the largest by this method.
// Examples:
// "19.0.0" > "19"
// "19.0.1" > "19.0.0"
// "19.1.0" > "19.0.1"
// "19" > "18.999.999"
int compareVersions(String a, String b) {
def aParts = a.tokenize('.').collect {it.toInteger()}
def bParts = b.tokenize('.').collect {it.toInteger()}
compareVersionList(aParts, bParts)
}
String getAndroidSdkDir() {
def rootDir = project.rootDir
def androidSdkDir = null
String envVar = System.getenv("ANDROID_HOME")
def localProperties = new File(rootDir, 'local.properties')
String systemProperty = System.getProperty("android.home")
if (envVar != null) {
androidSdkDir = envVar
} else if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDirProp = properties.getProperty('sdk.dir')
if (sdkDirProp != null) {
androidSdkDir = sdkDirProp
} else {
sdkDirProp = properties.getProperty('android.dir')
if (sdkDirProp != null) {
androidSdkDir = (new File(rootDir, sdkDirProp)).getAbsolutePath()
}
}
}
if (androidSdkDir == null && systemProperty != null) {
androidSdkDir = systemProperty
}
if (androidSdkDir == null) {
throw new RuntimeException(
"Unable to determine Android SDK directory.")
}
androidSdkDir
}
ext.cordovaSdkVersion = System.env.MIN_SDK_VERSION ?: getProjectTarget("android-19")
ext.cordovaBuildToolsVersion = latestBuildToolsAvailable("19.1.0")

View File

@@ -1,18 +0,0 @@
import java.util.regex.Pattern
def getProjectList() {
def manifestFile = file("project.properties")
def pattern = Pattern.compile("android.library.reference.(\\d+)\\s*=\\s*(.*)")
def matcher = pattern.matcher(manifestFile.getText())
def projects = []
while (matcher.find()) {
projects.add(":" + matcher.group(2).replace("/",":"))
}
return projects
}
for (subproject in getProjectList()) {
include subproject
}
include ':'

View File

@@ -1,5 +1,5 @@
// Platform: android
// 3.6.3
// 8ca0f3b2b87e0759c5236b91c80f18438544409c
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -19,7 +19,7 @@
under the License.
*/
;(function() {
var CORDOVA_JS_BUILD_LABEL = '3.6.3';
var PLATFORM_VERSION_BUILD_LABEL = '3.7.0-dev';
// file: src/scripts/require.js
/*jshint -W079 */
@@ -175,7 +175,8 @@ function createEvent(type, data) {
var cordova = {
define:define,
require:require,
version:CORDOVA_JS_BUILD_LABEL,
version:PLATFORM_VERSION_BUILD_LABEL,
platformVersion:PLATFORM_VERSION_BUILD_LABEL,
platformId:platform.id,
/**
* Methods to add/remove your own addEventListener hijacking on document + window.
@@ -1183,6 +1184,16 @@ function replaceNavigator(origNavigator) {
for (var key in origNavigator) {
if (typeof origNavigator[key] == 'function') {
newNavigator[key] = origNavigator[key].bind(origNavigator);
} else {
(function(k) {
Object.defineProperty(newNavigator, k, {
get: function() {
return origNavigator[k];
},
configurable: true,
enumerable: true
});
})(key);
}
}
}
@@ -1302,6 +1313,16 @@ function replaceNavigator(origNavigator) {
for (var key in origNavigator) {
if (typeof origNavigator[key] == 'function') {
newNavigator[key] = origNavigator[key].bind(origNavigator);
} else {
(function(k) {
Object.defineProperty(newNavigator, k, {
get: function() {
return origNavigator[k];
},
configurable: true,
enumerable: true
});
})(key);
}
}
}

View File

@@ -1,20 +1,19 @@
/*
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
/* 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
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.
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.
*/
@@ -25,15 +24,25 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:0.10.+'
// This should be updated with each cordova-android release.
// It can affect things like where the .apk is generated.
// It also dictates what the minimum android build-tools version
// that you need (Set in bin/templates/project/cordova.gradle).
// Make sure the value is the same in all locations:
// * framework/build.gradle
// * bin/templates/project/cordova.gradle
// * bin/templates/cordova/lib/plugin-build.gradle
// * distributionUrl within bin/templates/cordova/lib/build.js.
classpath 'com.android.tools.build:gradle:0.12.+'
}
}
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
compileSdkVersion cordova.cordovaSdkVersion
buildToolsVersion cordova.cordovaBuildToolsVersion
publishNonDefault true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7

View File

@@ -49,6 +49,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.ValueCallback;
@@ -72,6 +73,7 @@ import android.widget.LinearLayout;
* &#64;Override
* public void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* super.init();
* // Load your application
* loadUrl(launchUrl);
* }
@@ -200,14 +202,33 @@ public class CordovaActivity extends Activity implements CordovaInterface {
public void onCreate(Bundle savedInstanceState) {
LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting");
LOG.d(TAG, "CordovaActivity.onCreate()");
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
loadConfig();
if(!preferences.getBoolean("ShowTitle", false))
{
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
}
if(preferences.getBoolean("SetFullscreen", false))
{
Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else if (preferences.getBoolean("Fullscreen", false)) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
super.onCreate(savedInstanceState);
if(savedInstanceState != null)
{
initCallbackClass = savedInstanceState.getString("callbackClass");
}
loadConfig();
}
@SuppressWarnings("deprecation")
@@ -227,7 +248,9 @@ public class CordovaActivity extends Activity implements CordovaInterface {
@SuppressWarnings("deprecation")
protected void createViews() {
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
LOG.d(TAG, "CordovaActivity.createViews()");
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
@@ -245,6 +268,14 @@ public class CordovaActivity extends Activity implements CordovaInterface {
// Add web view but make it invisible while loading URL
appView.setVisibility(View.INVISIBLE);
// need to remove appView from any existing parent before invoking root.addView(appView)
ViewParent parent = appView.getParent();
if ((parent != null) && (parent != root)) {
LOG.d(TAG, "removing appView from existing parent");
ViewGroup parentGroup = (ViewGroup) parent;
parentGroup.removeView(appView);
}
root.addView((View) appView);
setContentView(root);
@@ -302,24 +333,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) {
LOG.d(TAG, "CordovaActivity.init()");
if(!preferences.getBoolean("ShowTitle", false))
{
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
}
if(preferences.getBoolean("SetFullscreen", false))
{
Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else if (preferences.getBoolean("Fullscreen", false)) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
appView = webView != null ? webView : makeWebView();
if (appView.pluginManager == null) {
appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView),

View File

@@ -65,6 +65,9 @@ public class CordovaChromeClient extends WebChromeClient {
// the video progress view
private View mVideoProgressView;
//Keep track of last AlertDialog showed
private AlertDialog lastHandledDialog;
// File Chooser
public ValueCallback<Uri> mUploadMessage;
@@ -123,7 +126,7 @@ public class CordovaChromeClient extends WebChromeClient {
return true;
}
});
dlg.show();
lastHandledDialog = dlg.show();
return true;
}
@@ -172,7 +175,7 @@ public class CordovaChromeClient extends WebChromeClient {
return true;
}
});
dlg.show();
lastHandledDialog = dlg.show();
return true;
}
@@ -216,7 +219,7 @@ public class CordovaChromeClient extends WebChromeClient {
res.cancel();
}
});
dlg.show();
lastHandledDialog = dlg.show();
}
return true;
}
@@ -328,4 +331,11 @@ public class CordovaChromeClient extends WebChromeClient {
public ValueCallback<Uri> getValueCallback() {
return this.mUploadMessage;
}
public void destroyLastDialog(){
if(lastHandledDialog != null){
lastHandledDialog.cancel();
}
}
}

View File

@@ -61,7 +61,7 @@ import android.widget.FrameLayout;
public class CordovaWebView extends WebView {
public static final String TAG = "CordovaWebView";
public static final String CORDOVA_VERSION = "3.6.0";
public static final String CORDOVA_VERSION = "3.7.0-dev";
private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
@@ -788,6 +788,9 @@ public class CordovaWebView extends WebView {
// Load blank page so that JavaScript onunload is called
this.loadUrl("about:blank");
//Remove last AlertDialog
this.chromeClient.destroyLastDialog();
// Forward to plugins
if (this.pluginManager != null) {

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-android",
"version": "3.6.0",
"version": "3.7.0-dev",
"description": "cordova-android release",
"main": "bin/create",
"repository": {
@@ -13,7 +13,8 @@
"apache"
],
"scripts": {
"test": "jasmine-node --color spec"
"test": "jasmine-node --color spec",
"test-build": "rm -rf \"test create\"; ./bin/create \"test create\" com.test.app Test && \"./test create/cordova/build\" && rm -rf \"test create\""
},
"author": "Apache Software Foundation",
"license": "Apache version 2.0",

View File

@@ -34,7 +34,7 @@ found at https://code.google.com/p/robotium/ and the jar should be put in the
To run manually from command line:
0. Build by entering `ant debug install`
0. Run tests by clicking on "CordovaTest" icon on device
0. Run tests by clicking on "CordovaNativeTests" app icon on the device
To run from Eclipse:

View File

@@ -34,6 +34,7 @@
<preference name="loglevel" value="DEBUG" />
<preference name="useBrowserHistory" value="true" />
<preference name="exit-on-suspend" value="false" />
<preference name="showTitle" value="true" />
<feature name="Activity">
<param name="android-package" value="org.apache.cordova.test.ActivityPlugin" />
</feature>

View File

@@ -75,6 +75,7 @@ public class IntentUriOverrideTest extends ActivityInstrumentationTestCase2<Sabo
runTestOnUiThread(new Runnable() {
public void run()
{
sleep();
boolean isBadUrl = testView.getUrl().equals(BAD_URL);
assertFalse(isBadUrl);
}

View File

@@ -32,8 +32,7 @@ public class menus extends CordovaActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// need the title to be shown for the options menu to be visible
preferences.set("showTitle", true);
// need the title to be shown (config.xml) for the options menu to be visible
super.init();
super.registerForContextMenu(super.appView);
super.loadUrl("file:///android_asset/www/menus/index.html");