Compare 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 GonzalezandAndrew Grieve 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 WoghirenandAndrew Grieve 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 WoghirenandAndrew Grieve 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
22 changed files with 468 additions and 299 deletions
+3
View File
@@ -37,3 +37,6 @@ Desktop.ini
# IntelliJ IDEA files
*.iml
.idea
npm-debug.log
/node_modules
/framework/build
+11
View File
@@ -20,6 +20,17 @@
-->
## 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)
+2 -1
View File
@@ -101,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 {
-1
View File
@@ -122,7 +122,6 @@ 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);
}
+134 -88
View File
@@ -32,23 +32,52 @@ 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) {
var timeDiff = b.t - a.t;
if (timeDiff === 0) {
return a.p.length - b.p.length;
fs.readdirSync(directory).forEach(function(p) {
if (path.extname(p) == '.apk') {
ret.push(path.join(directory, p));
}
return timeDiff;
}).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);
});
}
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() {
@@ -127,8 +156,6 @@ var builders = {
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args);
}).then(function() {
return builder.getOutputFiles();
});
},
@@ -140,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);
}
var ret = candidates[0];
return [ret];
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 = [
@@ -179,7 +193,15 @@ var builders = {
'copyDebugLint'
];
}
if (cmd == 'debug') {
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';
@@ -214,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);
});
},
@@ -221,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 = this.getArgs(build_type == 'debug' ? 'debug' : 'release');
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);
});
},
@@ -241,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) {
findOutputApks: function(build_type, arch) {
var binDir = path.join(ROOT, 'build', 'outputs', '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;
return findOutputApksHelper(binDir, build_type, arch);
}
},
@@ -265,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':
@@ -305,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;
}
@@ -327,27 +375,21 @@ 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);
var builtApks = [];
for (var i=0; i < apkFiles.length; ++i) {
var dst = path.join(outputDir, path.basename(apkFiles[i]));
builtApks.push(dst);
shell.cp('-f', apkFiles[i], dst);
}
console.log('Built the following APKs:\n' + builtApks.join('\n'));
return builtApks;
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
};
});
};
@@ -365,21 +407,25 @@ module.exports.detectArchitecture = function(target) {
});
};
/*
* 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
*/
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.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() {
+42 -30
View File
@@ -43,20 +43,14 @@ module.exports.list = function() {
});
}
/*
* Installs a previously built application on the device
* and launches it.
* Returns a promise.
*/
module.exports.install = function(target) {
var launchName;
module.exports.resolveTarget = function(target) {
return this.list()
.then(function(device_list) {
if (!device_list || !device_list.length)
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];
target = target || device_list[0];
if (device_list.indexOf(target) < 0) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
@@ -64,27 +58,45 @@ module.exports.install = function(target) {
return build.detectArchitecture(target)
.then(function(arch) {
var apk_path = build.get_apk(null, arch);
launchName = appinfo.getActivityName();
console.log('Installing app on device...');
var cmd = 'adb -s ' + target + ' install -r "' + apk_path + '"';
return exec(cmd);
return { target: target, arch: arch, isEmulator: false };
});
}).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);
/*
* Installs a previously built application on the device
* and launches it.
* Returns a promise.
*/
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var launchName = appinfo.getActivityName();
console.log('Using apk: ' + apk_path);
console.log('Installing app on device...');
var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
return exec(cmd)
.then(function(output) {
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
//unlock screen
var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
return exec(cmd);
}, 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);
});
});
}
+43 -31
View File
@@ -273,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) {
@@ -288,36 +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.');
}
return build.detectArchitecture(target)
.then(function(arch) {
var apk_path = build.get_apk(null, arch);
console.log('Installing app on emulator...');
return exec('adb -s ' + target + ' install -r "' + apk_path + '"');
return {target:target, arch:arch, isEmulator:true};
});
}).then(function(output) {
if (output.match(/Failure/)) {
return Q.reject('Failed to install apk to emulator: ' + output);
});
};
/*
* 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);
});
});
}
@@ -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'
}
+55 -62
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);
});
});
}
+1
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);
}
+14 -20
View File
@@ -17,6 +17,8 @@
under the License.
*/
// GENERATED FILE! DO NOT EDIT!
import java.util.regex.Pattern
import groovy.swing.SwingBuilder
@@ -34,15 +36,12 @@ buildscript {
}
}
ext.multiarch=false
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
for (subproject in getProjectList()) {
compile project(subproject)
}
task wrapper(type: Wrapper) {
gradleVersion = '1.12'
}
ext.multiarch=false
android {
sourceSets {
main {
@@ -112,10 +111,13 @@ android {
}
}
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
@@ -169,17 +171,6 @@ 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("/",":"))
}
return projects
}
def ensureValueExists(filePath, props, key) {
if (props.get(key) == null) {
throw new GradleException(filePath + ': Missing key required "' + key + '"')
@@ -199,3 +190,6 @@ def addSigningProps(propsFilePath, signingConfig) {
}
}
if (file('build-extras.gradle').exists()) {
apply from: 'build-extras.gradle'
}
+2 -2
View File
@@ -115,6 +115,6 @@ String getAndroidSdkDir() {
androidSdkDir
}
cordovaSdkVersion = System.env.MIN_SDK_VERSION ?: getProjectTarget("android-19")
cordovaBuildToolsVersion = latestBuildToolsAvailable("19.1.0")
ext.cordovaSdkVersion = System.env.MIN_SDK_VERSION ?: getProjectTarget("android-19")
ext.cordovaBuildToolsVersion = latestBuildToolsAvailable("19.1.0")
-18
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 ':'
+24 -3
View File
@@ -1,5 +1,5 @@
// Platform: android
// 3.7.0-dev-1258511
// 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.7.0-dev-1258511';
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);
}
}
}
+20 -16
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.
*/
@@ -29,7 +28,11 @@ buildscript {
// 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).
// Be sure to also update the value in bin/templates/project.
// 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.+'
}
}
@@ -39,6 +42,7 @@ apply plugin: 'android-library'
android {
compileSdkVersion cordova.cordovaSdkVersion
buildToolsVersion cordova.cordovaBuildToolsVersion
publishNonDefault true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
@@ -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),
@@ -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();
}
}
}
@@ -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) {
+1 -1
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:
+1
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>
@@ -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);
}
+1 -2
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");