diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index fb0a709c99..304403b8ac 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -20,6 +20,40 @@
-->
## Release Notes for Cordova (Android) ##
+### Release 3.7.2 (May 2015) ###
+
+* Removed Intent Functionality from Preferences - Preferences can no longer be set by intents
+
+### Release 3.7.1 (January 2015) ###
+* CB-8411 Initialize plugins only after `createViews()` is called (regression in 3.7.0)
+
+### Release 3.7.0 (January 2015) ###
+
+* CB-8328 Allow plugins to handle certificate challenges (close #150)
+* CB-8201 Add support for auth dialogs into Cordova Android
+* CB-8017 Add support for `` for Lollipop
+* CB-8143 Loads of gradle improvements (try it with cordova/build --gradle)
+* CB-8329 Cancel outstanding ActivityResult requests when a new startActivityForResult occurs
+* CB-8026 Bumping up Android Version and setting it up to allow third-party cookies. This might change later.
+* CB-8210 Use PluginResult for various events from native so that content-security-policy can be used
+* CB-8168 Add support for `cordova/run --list` (closes #139)
+* CB-8176 Vastly better auto-detection of SDK & JDK locations
+* CB-8079 Use activity class package name, but fallback to application package name when looking for splash screen drawable
+* CB-8147 Have corodva/build warn about unrecognized flags rather than fail
+* CB-7881 Android tooling shouldn't lock application directory
+* CB-8112 Turn off mediaPlaybackRequiresUserGesture
+* CB-6153 Add a preference for controlling hardware button audio stream (DefaultVolumeStream)
+* CB-8031 Fix race condition that shows as ConcurrentModificationException
+* CB-7974 Cancel timeout timer if view is destroyed
+* CB-7940 Disable exec bridge if bridgeSecret is wrong
+* CB-7758 Allow content-url-hosted pages to access the bridge
+* CB-6511 Fixes build for android when app name contains unicode characters.
+* CB-7707 Added multipart PluginResult
+* CB-6837 Fix leaked window when hitting back button while alert being rendered
+* CB-7674 Move preference activation back into onCreate()
+* CB-7499 Support RTL text direction
+* CB-7330 Don't run check_reqs for bin/create.
+
### 3.6.4 (Sept 30, 2014) ###
* Set VERSION to 3.6.4 (via coho)
diff --git a/VERSION b/VERSION
index a4ce38ebae..0b2eb36f50 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.7.0-dev
+3.7.2
diff --git a/bin/lib/create.js b/bin/lib/create.js
index c0d0c50f06..5471bb4da3 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -72,6 +72,7 @@ function copyJsAndLibrary(projectPath, shared, projectName) {
shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
+ shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
// Create an eclipse project file and set the name of it to something unique.
// Without this, you can't import multiple CordovaLib projects into the same workspace.
@@ -122,7 +123,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, 'cordova.gradle'), projectPath);
}
function copyScripts(projectPath) {
diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js
index 5ad3e76f0e..e441caa711 100644
--- a/bin/templates/cordova/lib/build.js
+++ b/bin/templates/cordova/lib/build.js
@@ -69,11 +69,13 @@ function findOutputApksHelper(dir, build_type, arch) {
if (ret.length === 0) {
return ret;
}
+ // Assume arch-specific build if newest api has -x86 or -arm.
var archSpecific = !!/-x86|-arm/.exec(ret[0]);
+ // And show only arch-specific ones (or non-arch-specific)
ret = ret.filter(function(p) {
return !!/-x86|-arm/.exec(p) == archSpecific;
});
- if (arch) {
+ if (arch && ret.length > 1) {
ret = ret.filter(function(p) {
return p.indexOf('-' + arch) != -1;
});
@@ -175,20 +177,16 @@ var builders = {
},
gradle: {
getArgs: function(cmd, arch, extraArgs) {
- 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';
+ if (cmd == 'release') {
+ cmd = 'cdvBuildRelease';
} else if (cmd == 'debug') {
- cmd = 'assembleDebug';
- } else if (cmd == 'release') {
- cmd = 'assembleRelease';
+ cmd = 'cdvBuildDebug';
}
var args = [cmd, '-b', path.join(ROOT, 'build.gradle')];
+ if (arch) {
+ args.push('-PcdvBuildArch=' + arch);
+ }
+
// 10 seconds -> 6 seconds
args.push('-Dorg.gradle.daemon=true');
args.push.apply(args, extraArgs);
@@ -260,7 +258,7 @@ var builders = {
var wrapper = path.join(ROOT, 'gradlew');
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release', arch, extraArgs);
return Q().then(function() {
- console.log('Running: ' + wrapper + ' ' + extraArgs.join(' '));
+ console.log('Running: ' + wrapper + ' ' + args.concat(extraArgs).join(' '));
return spawn(wrapper, args);
});
},
@@ -270,7 +268,7 @@ var builders = {
var wrapper = path.join(ROOT, 'gradlew');
var args = builder.getArgs('clean', null, extraArgs);
return Q().then(function() {
- console.log('Running: ' + wrapper + ' ' + extraArgs.join(' '));
+ console.log('Running: ' + wrapper + ' ' + args.concat(extraArgs).join(' '));
return spawn(wrapper, args);
});
},
@@ -319,8 +317,8 @@ function parseOpts(options, resolvedTarget) {
for (var i=0; options && (i < options.length); ++i) {
if (/^--/.exec(options[i])) {
var keyValue = options[i].substring(2).split('=');
- var flagName = keyValue[0];
- var flagValue = keyValue[1];
+ var flagName = keyValue.shift();
+ var flagValue = keyValue.join('=');
if (multiValueArgs[flagName] && !flagValue) {
flagValue = options[i + 1];
++i;
@@ -359,10 +357,7 @@ function parseOpts(options, resolvedTarget) {
}
}
- var multiApk = ret.buildMethod == 'gradle' && process.env['BUILD_MULTIPLE_APKS'];
- if (multiApk && !/0|false|no/i.exec(multiApk)) {
- ret.arch = resolvedTarget && resolvedTarget.arch;
- }
+ ret.arch = resolvedTarget && resolvedTarget.arch;
return ret;
}
diff --git a/bin/templates/cordova/lib/run.js b/bin/templates/cordova/lib/run.js
index db783d9126..ced23a09fc 100644
--- a/bin/templates/cordova/lib/run.js
+++ b/bin/templates/cordova/lib/run.js
@@ -39,7 +39,7 @@ var path = require('path'),
var list = false;
for (var i=2; i
}
}
-def ensureValueExists(filePath, props, key) {
- if (props.get(key) == null) {
- throw new GradleException(filePath + ': Missing key required "' + key + '"')
- }
- return props.get(key)
-}
-
def addSigningProps(propsFilePath, signingConfig) {
def propsFile = file(propsFilePath)
def props = new Properties()
propsFile.withReader { reader ->
props.load(reader)
}
- def storeFile = new File(ensureValueExists(propsFilePath, props, 'storeFile'))
+ def storeFile = new File(privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
if (!storeFile.isAbsolute()) {
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
}
if (!storeFile.exists()) {
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
}
- signingConfig.keyAlias = ensureValueExists(propsFilePath, props, 'keyAlias')
+ signingConfig.keyAlias = privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
signingConfig.keyPassword = props.get('keyPassword', signingConfig.keyPassword)
signingConfig.storeFile = storeFile
signingConfig.storePassword = props.get('storePassword', signingConfig.storePassword)
diff --git a/framework/assets/www/cordova.js b/framework/assets/www/cordova.js
index 2fcf2469b9..07c7c6ee3c 100644
--- a/framework/assets/www/cordova.js
+++ b/framework/assets/www/cordova.js
@@ -1,5 +1,5 @@
// Platform: android
-// ee7b91f28e3780afb44222a2d950ccc1bebd0b87
+// 24ab6855470f2dc0662624b597c98585e56a1666
/*
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 PLATFORM_VERSION_BUILD_LABEL = '3.7.0-dev';
+var PLATFORM_VERSION_BUILD_LABEL = '3.7.2';
// file: src/scripts/require.js
/*jshint -W079 */
@@ -1977,4 +1977,4 @@ window.cordova = require('cordova');
require('cordova/init');
-})();
\ No newline at end of file
+})();
diff --git a/framework/build.gradle b/framework/build.gradle
index cace204294..2565633ffe 100644
--- a/framework/build.gradle
+++ b/framework/build.gradle
@@ -23,23 +23,21 @@ buildscript {
mavenCentral()
}
- dependencies {
- // Switch the Android Gradle plugin version requirement depending on the
- // installed version of Gradle. This dependency is documented at
- // http://tools.android.com/tech-docs/new-build-system/version-compatibility
- // and https://issues.apache.org/jira/browse/CB-8143
- if (gradle.gradleVersion >= "2.2") {
- dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0+'
- }
- } else if (gradle.gradleVersion >= "2.1") {
- dependencies {
- classpath 'com.android.tools.build:gradle:0.14.0+'
- }
- } else {
- dependencies {
- classpath 'com.android.tools.build:gradle:0.12.0+'
- }
+ // Switch the Android Gradle plugin version requirement depending on the
+ // installed version of Gradle. This dependency is documented at
+ // http://tools.android.com/tech-docs/new-build-system/version-compatibility
+ // and https://issues.apache.org/jira/browse/CB-8143
+ if (gradle.gradleVersion >= "2.2") {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.0.0+'
+ }
+ } else if (gradle.gradleVersion >= "2.1") {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.14.0+'
+ }
+ } else {
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.12.0+'
}
}
}
diff --git a/bin/templates/project/cordova.gradle b/framework/cordova.gradle
similarity index 84%
rename from bin/templates/project/cordova.gradle
rename to framework/cordova.gradle
index 8b371bf99b..5ce93f8ff4 100644
--- a/bin/templates/project/cordova.gradle
+++ b/framework/cordova.gradle
@@ -20,16 +20,19 @@
import java.util.regex.Pattern
import groovy.swing.SwingBuilder
+String doEnsureValueExists(filePath, props, key) {
+ if (props.get(key) == null) {
+ throw new GradleException(filePath + ': Missing key required "' + key + '"')
+ }
+ return props.get(key)
+}
-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 doGetProjectTarget() {
+ def props = new Properties()
+ file('project.properties').withReader { reader ->
+ props.load(reader)
}
+ return doEnsureValueExists('project.properties', props, 'target')
}
String[] getAvailableBuildTools() {
@@ -39,7 +42,7 @@ String[] getAvailableBuildTools() {
.sort { a, b -> compareVersions(b, a) }
}
-String findLatestInstalledBuildTools(String minBuildToolsVersion) {
+String doFindLatestInstalledBuildTools(String minBuildToolsVersion) {
def availableBuildToolsVersions
try {
availableBuildToolsVersions = getAvailableBuildTools()
@@ -117,7 +120,7 @@ String getAndroidSdkDir() {
androidSdkDir
}
-def extractIntFromManifest(name) {
+def doExtractIntFromManifest(name) {
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
def pattern = Pattern.compile(name + "=\"(\\d+)\"")
def matcher = pattern.matcher(manifestFile.getText())
@@ -125,7 +128,7 @@ def extractIntFromManifest(name) {
return Integer.parseInt(matcher.group(1))
}
-def promptForPassword(msg) {
+def doPromptForPassword(msg) {
if (System.console() == null) {
def ret = null
new SwingBuilder().edt {
@@ -153,9 +156,10 @@ def promptForPassword(msg) {
ext {
// These helpers are shared, but are not guaranteed to be stable / unchanged.
privateHelpers = {}
- privateHelpers.getProjectTarget = { defaultValue -> getProjectTarget(defaultValue) }
- privateHelpers.findLatestInstalledBuildTools = { defaultValue -> findLatestInstalledBuildTools(defaultValue) }
- privateHelpers.extractIntFromManifest = { name -> extractIntFromManifest(name) }
- privateHelpers.promptForPassword = { msg -> promptForPassword(msg) }
+ privateHelpers.getProjectTarget = { doGetProjectTarget() }
+ privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') }
+ privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
+ privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) }
+ privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
}
diff --git a/framework/src/org/apache/cordova/Config.java b/framework/src/org/apache/cordova/Config.java
index f13292c3f1..53c6871278 100644
--- a/framework/src/org/apache/cordova/Config.java
+++ b/framework/src/org/apache/cordova/Config.java
@@ -37,7 +37,6 @@ public static void init(Activity action) {
parser = new ConfigXmlParser();
parser.parse(action);
parser.getPreferences().setPreferencesBundle(action.getIntent().getExtras());
- parser.getPreferences().copyIntoIntentExtras(action);
}
// Intended to be used for testing only; creates an empty configuration.
diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java
index b61fa98707..4d6a40374c 100755
--- a/framework/src/org/apache/cordova/CordovaActivity.java
+++ b/framework/src/org/apache/cordova/CordovaActivity.java
@@ -36,7 +36,6 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.content.Intent;
import android.graphics.Color;
import android.media.AudioManager;
-import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
@@ -48,7 +47,6 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
-import android.webkit.ValueCallback;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
@@ -103,7 +101,8 @@ public class CordovaActivity extends Activity implements CordovaInterface {
private int activityState = 0; // 0=starting, 1=running (after 1st resume), 2=shutting down
// Plugin to call when activity result is received
- protected CordovaPlugin activityResultCallback = null;
+ protected int activityResultRequestCode;
+ protected CordovaPlugin activityResultCallback;
protected boolean activityResultKeepRunning;
/*
@@ -233,7 +232,6 @@ protected void loadConfig() {
parser.parse(this);
preferences = parser.getPreferences();
preferences.setPreferencesBundle(getIntent().getExtras());
- preferences.copyIntoIntentExtras(this);
internalWhitelist = parser.getInternalWhitelist();
externalWhitelist = parser.getExternalWhitelist();
launchUrl = parser.getLaunchUrl();
@@ -334,11 +332,6 @@ public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, Cor
}
appView = webView != null ? webView : makeWebView();
- if (appView.pluginManager == null) {
- appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView),
- webChromeClient != null ? webChromeClient : makeChromeClient(appView),
- pluginEntries, internalWhitelist, externalWhitelist, preferences);
- }
// TODO: Have the views set this themselves.
if (preferences.getBoolean("DisallowOverscroll", false)) {
@@ -346,6 +339,13 @@ public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, Cor
}
createViews();
+ // Init plugins only after creating views
+ if (appView.pluginManager == null) {
+ appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView),
+ webChromeClient != null ? webChromeClient : makeChromeClient(appView),
+ pluginEntries, internalWhitelist, externalWhitelist, preferences);
+ }
+
// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
@@ -666,7 +666,7 @@ public void endActivity() {
* @param requestCode The request code that is passed to callback to identify the activity
*/
public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
- this.activityResultCallback = command;
+ setActivityResultCallback(command);
this.activityResultKeepRunning = this.keepRunning;
// If multitasking turned on, then disable it for activities that return results
@@ -674,8 +674,19 @@ public void startActivityForResult(CordovaPlugin command, Intent intent, int req
this.keepRunning = false;
}
- // Start activity
- super.startActivityForResult(intent, requestCode);
+ try {
+ startActivityForResult(intent, requestCode);
+ } catch (RuntimeException e) { // E.g.: ActivityNotFoundException
+ activityResultCallback = null;
+ throw e;
+ }
+ }
+
+ @Override
+ public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
+ // Capture requestCode here so that it is captured in the setActivityResultCallback() case.
+ activityResultRequestCode = requestCode;
+ super.startActivityForResult(intent, requestCode, options);
}
/**
@@ -685,37 +696,34 @@ public void startActivityForResult(CordovaPlugin command, Intent intent, int req
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
- * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+ * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- LOG.d(TAG, "Incoming Result");
+ LOG.d(TAG, "Incoming Result. Request code = " + requestCode);
super.onActivityResult(requestCode, resultCode, intent);
- Log.d(TAG, "Request code = " + requestCode);
- if (appView != null && requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
- ValueCallback mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
- Log.d(TAG, "did we get here?");
- if (null == mUploadMessage)
- return;
- Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
- Log.d(TAG, "result = " + result);
- mUploadMessage.onReceiveValue(result);
- mUploadMessage = null;
- }
CordovaPlugin callback = this.activityResultCallback;
if(callback == null && initCallbackClass != null) {
// The application was restarted, but had defined an initial callback
// before being shut down.
- this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
- callback = this.activityResultCallback;
+ callback = appView.pluginManager.getPlugin(initCallbackClass);
}
- if(callback != null) {
+ initCallbackClass = null;
+ activityResultCallback = null;
+
+ if (callback != null) {
LOG.d(TAG, "We have a callback to send this result to");
callback.onActivityResult(requestCode, resultCode, intent);
+ } else {
+ LOG.w(TAG, "Got an activity result, but no plugin was registered to receive it.");
}
}
public void setActivityResultCallback(CordovaPlugin plugin) {
+ // Cancel any previously pending activity.
+ if (activityResultCallback != null) {
+ activityResultCallback.onActivityResult(activityResultRequestCode, Activity.RESULT_CANCELED, null);
+ }
this.activityResultCallback = plugin;
}
diff --git a/framework/src/org/apache/cordova/CordovaChromeClient.java b/framework/src/org/apache/cordova/CordovaChromeClient.java
index ff0c0f2f78..31759d0aa5 100755
--- a/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -22,10 +22,14 @@ Licensed to the Apache Software Foundation (ASF) under one
import org.apache.cordova.LOG;
import android.annotation.TargetApi;
+import android.app.Activity;
import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
+import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
@@ -67,10 +71,7 @@ public class CordovaChromeClient extends WebChromeClient {
//Keep track of last AlertDialog showed
private AlertDialog lastHandledDialog;
-
- // File Chooser
- public ValueCallback mUploadMessage;
-
+
@Deprecated
public CordovaChromeClient(CordovaInterface cordova) {
this.cordova = cordova;
@@ -309,7 +310,10 @@ public View getVideoLoadingProgressView() {
}
return mVideoProgressView;
}
-
+
+ // support:
+ // openFileChooser() is for pre KitKat and in KitKat mr1 (it's known broken in KitKat).
+ // For Lollipop, we use onShowFileChooser().
public void openFileChooser(ValueCallback uploadMsg) {
this.openFileChooser(uploadMsg, "*/*");
}
@@ -318,20 +322,41 @@ public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
this.openFileChooser(uploadMsg, acceptType, null);
}
- public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture)
+ public void openFileChooser(final ValueCallback uploadMsg, String acceptType, String capture)
{
- mUploadMessage = uploadMsg;
- Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.addCategory(Intent.CATEGORY_OPENABLE);
- i.setType("*/*");
- this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
- FILECHOOSER_RESULTCODE);
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ cordova.startActivityForResult(new CordovaPlugin() {
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
+ Log.d(TAG, "Receive file chooser URL: " + result);
+ uploadMsg.onReceiveValue(result);
+ }
+ }, intent, FILECHOOSER_RESULTCODE);
}
-
- public ValueCallback getValueCallback() {
- return this.mUploadMessage;
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public boolean onShowFileChooser(WebView webView, final ValueCallback filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
+ Intent intent = fileChooserParams.createIntent();
+ try {
+ cordova.startActivityForResult(new CordovaPlugin() {
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
+ Log.d(TAG, "Receive file chooser URL: " + result);
+ filePathsCallback.onReceiveValue(result);
+ }
+ }, intent, FILECHOOSER_RESULTCODE);
+ } catch (ActivityNotFoundException e) {
+ Log.w("No activity found to handle file chooser intent.", e);
+ filePathsCallback.onReceiveValue(null);
+ }
+ return true;
}
-
+
public void destroyLastDialog(){
if(lastHandledDialog != null){
lastHandledDialog.cancel();
diff --git a/framework/src/org/apache/cordova/CordovaClientCertRequest.java b/framework/src/org/apache/cordova/CordovaClientCertRequest.java
new file mode 100644
index 0000000000..5dd0ecaec5
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaClientCertRequest.java
@@ -0,0 +1,96 @@
+/*
+ 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.
+*/
+package org.apache.cordova;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import android.webkit.ClientCertRequest;
+
+/**
+ * Implementation of the ICordovaClientCertRequest for Android WebView.
+ */
+public class CordovaClientCertRequest implements ICordovaClientCertRequest {
+
+ private final ClientCertRequest request;
+
+ public CordovaClientCertRequest(ClientCertRequest request) {
+ this.request = request;
+ }
+
+ /**
+ * Cancel this request
+ */
+ public void cancel()
+ {
+ request.cancel();
+ }
+
+ /*
+ * Returns the host name of the server requesting the certificate.
+ */
+ public String getHost()
+ {
+ return request.getHost();
+ }
+
+ /*
+ * Returns the acceptable types of asymmetric keys (can be null).
+ */
+ public String[] getKeyTypes()
+ {
+ return request.getKeyTypes();
+ }
+
+ /*
+ * Returns the port number of the server requesting the certificate.
+ */
+ public int getPort()
+ {
+ return request.getPort();
+ }
+
+ /*
+ * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
+ */
+ public Principal[] getPrincipals()
+ {
+ return request.getPrincipals();
+ }
+
+ /*
+ * Ignore the request for now. Do not remember user's choice.
+ */
+ public void ignore()
+ {
+ request.ignore();
+ }
+
+ /*
+ * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
+ *
+ * @param privateKey The privateKey
+ * @param chain The certificate chain
+ */
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain)
+ {
+ request.proceed(privateKey, chain);
+ }
+}
diff --git a/framework/src/org/apache/cordova/CordovaHttpAuthHandler.java b/framework/src/org/apache/cordova/CordovaHttpAuthHandler.java
new file mode 100644
index 0000000000..724381e2c1
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaHttpAuthHandler.java
@@ -0,0 +1,51 @@
+/*
+ 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.
+*/
+package org.apache.cordova;
+
+import android.webkit.HttpAuthHandler;
+
+/**
+ * Specifies interface for HTTP auth handler object which is used to handle auth requests and
+ * specifying user credentials.
+ */
+public class CordovaHttpAuthHandler implements ICordovaHttpAuthHandler {
+
+ private final HttpAuthHandler handler;
+
+ public CordovaHttpAuthHandler(HttpAuthHandler handler) {
+ this.handler = handler;
+ }
+
+ /**
+ * Instructs the WebView to cancel the authentication request.
+ */
+ public void cancel () {
+ this.handler.cancel();
+ }
+
+ /**
+ * Instructs the WebView to proceed with the authentication with the given credentials.
+ *
+ * @param username
+ * @param password
+ */
+ public void proceed (String username, String password) {
+ this.handler.proceed(username, password);
+ }
+}
diff --git a/framework/src/org/apache/cordova/CordovaPlugin.java b/framework/src/org/apache/cordova/CordovaPlugin.java
index a68d3d7eb8..1748407ab1 100644
--- a/framework/src/org/apache/cordova/CordovaPlugin.java
+++ b/framework/src/org/apache/cordova/CordovaPlugin.java
@@ -198,4 +198,34 @@ public Uri remapUri(Uri uri) {
*/
public void onReset() {
}
+
+ /**
+ * Called when the system received an HTTP authentication request. Plugin can use
+ * the supplied HttpAuthHandler to process this auth challenge.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param handler The HttpAuthHandler used to set the WebView's response
+ * @param host The host requiring authentication
+ * @param realm The realm for which authentication is required
+ *
+ * @return Returns True if plugin will resolve this auth challenge, otherwise False
+ *
+ */
+ public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
+ return false;
+ }
+
+ /**
+ * Called when he system received an SSL client certificate request. Plugin can use
+ * the supplied ClientCertRequest to process this certificate challenge.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param request The client certificate request
+ *
+ * @return Returns True if plugin will resolve this auth challenge, otherwise False
+ *
+ */
+ public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
+ return false;
+ }
}
diff --git a/framework/src/org/apache/cordova/CordovaPreferences.java b/framework/src/org/apache/cordova/CordovaPreferences.java
index ed0b9b8951..27fb82682f 100644
--- a/framework/src/org/apache/cordova/CordovaPreferences.java
+++ b/framework/src/org/apache/cordova/CordovaPreferences.java
@@ -61,13 +61,6 @@ public boolean getBoolean(String name, boolean defaultValue) {
String value = prefs.get(name);
if (value != null) {
return Boolean.parseBoolean(value);
- } else if (preferencesBundleExtras != null) {
- Object bundleValue = preferencesBundleExtras.get(name);
- if (bundleValue instanceof String) {
- return "true".equals(bundleValue);
- }
- // Gives a nice warning if type is wrong.
- return preferencesBundleExtras.getBoolean(name, defaultValue);
}
return defaultValue;
}
@@ -78,13 +71,6 @@ public int getInteger(String name, int defaultValue) {
if (value != null) {
// Use Integer.decode() can't handle it if the highest bit is set.
return (int)(long)Long.decode(value);
- } else if (preferencesBundleExtras != null) {
- Object bundleValue = preferencesBundleExtras.get(name);
- if (bundleValue instanceof String) {
- return Integer.valueOf((String)bundleValue);
- }
- // Gives a nice warning if type is wrong.
- return preferencesBundleExtras.getInt(name, defaultValue);
}
return defaultValue;
}
@@ -94,14 +80,7 @@ public double getDouble(String name, double defaultValue) {
String value = prefs.get(name);
if (value != null) {
return Double.valueOf(value);
- } else if (preferencesBundleExtras != null) {
- Object bundleValue = preferencesBundleExtras.get(name);
- if (bundleValue instanceof String) {
- return Double.valueOf((String)bundleValue);
- }
- // Gives a nice warning if type is wrong.
- return preferencesBundleExtras.getDouble(name, defaultValue);
- }
+ }
return defaultValue;
}
@@ -110,69 +89,8 @@ public String getString(String name, String defaultValue) {
String value = prefs.get(name);
if (value != null) {
return value;
- } else if (preferencesBundleExtras != null && !"errorurl".equals(name)) {
- Object bundleValue = preferencesBundleExtras.get(name);
- if (bundleValue != null) {
- return bundleValue.toString();
- }
- }
+ }
return defaultValue;
}
- // Plugins should not rely on values within the intent since this does not work
- // for apps with multiple webviews. Instead, they should retrieve prefs from the
- // Config object associated with their webview.
- public void copyIntoIntentExtras(Activity action) {
- for (String name : prefs.keySet()) {
- String value = prefs.get(name);
- if (value == null) {
- continue;
- }
- if (name.equals("loglevel")) {
- LOG.setLogLevel(value);
- } else if (name.equals("splashscreen")) {
- // Note: We should probably pass in the classname for the variable splash on splashscreen!
- int resource = action.getResources().getIdentifier(value, "drawable", action.getClass().getPackage().getName());
- if(resource == 0) {
- resource = action.getResources().getIdentifier(value, "drawable", action.getPackageName());
- }
- action.getIntent().putExtra(name, resource);
- }
- else if(name.equals("backgroundcolor")) {
- int asInt = (int)(long)Long.decode(value);
- action.getIntent().putExtra(name, asInt);
- }
- else if(name.equals("loadurltimeoutvalue")) {
- int asInt = Integer.decode(value);
- action.getIntent().putExtra(name, asInt);
- }
- else if(name.equals("splashscreendelay")) {
- int asInt = Integer.decode(value);
- action.getIntent().putExtra(name, asInt);
- }
- else if(name.equals("keeprunning"))
- {
- boolean asBool = Boolean.parseBoolean(value);
- action.getIntent().putExtra(name, asBool);
- }
- else if(name.equals("inappbrowserstorageenabled"))
- {
- boolean asBool = Boolean.parseBoolean(value);
- action.getIntent().putExtra(name, asBool);
- }
- else if(name.equals("disallowoverscroll"))
- {
- boolean asBool = Boolean.parseBoolean(value);
- action.getIntent().putExtra(name, asBool);
- }
- else
- {
- action.getIntent().putExtra(name, value);
- }
- }
- // In the normal case, the intent extras are null until the first call to putExtra().
- if (preferencesBundleExtras == null) {
- preferencesBundleExtras = action.getIntent().getExtras();
- }
- }
}
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 8c6e47121b..14919c4b79 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -62,7 +62,7 @@ Licensed to the Apache Software Foundation (ASF) under one
public class CordovaWebView extends WebView {
public static final String TAG = "CordovaWebView";
- public static final String CORDOVA_VERSION = "3.7.0-dev";
+ public static final String CORDOVA_VERSION = "3.7.2";
private HashSet boundKeyCodes = new HashSet();
@@ -405,7 +405,7 @@ public void loadUrlIntoView(final String url, boolean recreatePlugins) {
// Create a timeout timer for loadUrl
final CordovaWebView me = this;
final int currentLoadUrlTimeout = me.loadUrlTimeout;
- final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000"));
+ final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
// Timeout error method
final Runnable loadError = new Runnable() {
@@ -454,7 +454,7 @@ void loadUrlNow(String url) {
if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
LOG.d(TAG, ">>> loadUrlNow()");
}
- if (url.startsWith("file://") || url.startsWith("javascript:") || internalWhitelist.isUrlWhiteListed(url)) {
+ if (url.startsWith("file://") || url.startsWith("javascript:") || url.startsWith("about:") || internalWhitelist.isUrlWhiteListed(url)) {
super.loadUrl(url);
}
}
@@ -609,26 +609,6 @@ public void showWebPage(String url, boolean openExternal, boolean clearHistory,
}
}
- /**
- * Get string property for activity.
- *
- * @param name
- * @param defaultValue
- * @return the String value for the named property
- */
- public String getProperty(String name, String defaultValue) {
- Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
- if (bundle == null) {
- return defaultValue;
- }
- name = name.toLowerCase(Locale.getDefault());
- Object p = bundle.get(name);
- if (p == null) {
- return defaultValue;
- }
- return p.toString();
- }
-
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java
index f65a9760fe..6b3b46085a 100755
--- a/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -21,7 +21,6 @@ Licensed to the Apache Software Foundation (ASF) under one
import java.util.Hashtable;
import org.apache.cordova.CordovaInterface;
-
import org.apache.cordova.LOG;
import org.json.JSONException;
import org.json.JSONObject;
@@ -33,6 +32,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.view.View;
+import android.webkit.ClientCertRequest;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
@@ -115,15 +115,45 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
- // Get the authentication token
+ // Get the authentication token (if specified)
AuthenticationToken token = this.getAuthenticationToken(host, realm);
if (token != null) {
handler.proceed(token.getUserName(), token.getPassword());
+ return;
+ }
+
+ // Check if there is some plugin which can resolve this auth challenge
+ PluginManager pluginManager = this.appView.pluginManager;
+ if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(this.appView, new CordovaHttpAuthHandler(handler), host, realm)) {
+ this.appView.loadUrlTimeout++;
+ return;
}
- else {
- // Handle 401 like we'd normally do!
- super.onReceivedHttpAuthRequest(view, handler, host, realm);
+
+ // By default handle 401 like we'd normally do!
+ super.onReceivedHttpAuthRequest(view, handler, host, realm);
+ }
+
+ /**
+ * On received client cert request.
+ * The method forwards the request to any running plugins before using the default implementation.
+ *
+ * @param view
+ * @param request
+ */
+ @Override
+ @TargetApi(21)
+ public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
+ {
+
+ // Check if there is some plugin which can resolve this certificate request
+ PluginManager pluginManager = this.appView.pluginManager;
+ if (pluginManager != null && pluginManager.onReceivedClientCertRequest(this.appView, new CordovaClientCertRequest(request))) {
+ this.appView.loadUrlTimeout++;
+ return;
}
+
+ // By default pass to WebViewClient
+ super.onReceivedClientCertRequest(view, request);
}
/**
@@ -163,8 +193,8 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
- // Ignore excessive calls.
- if (!isCurrentlyLoading) {
+ // Ignore excessive calls, if url is not about:blank (CB-8317).
+ if (!isCurrentlyLoading && !url.startsWith("about:")) {
return;
}
isCurrentlyLoading = false;
diff --git a/framework/src/org/apache/cordova/ICordovaClientCertRequest.java b/framework/src/org/apache/cordova/ICordovaClientCertRequest.java
new file mode 100644
index 0000000000..455d2f9d35
--- /dev/null
+++ b/framework/src/org/apache/cordova/ICordovaClientCertRequest.java
@@ -0,0 +1,66 @@
+/*
+ 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.
+*/
+package org.apache.cordova;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * Specifies interface for handling certificate requests.
+ */
+public interface ICordovaClientCertRequest {
+ /**
+ * Cancel this request
+ */
+ public void cancel();
+
+ /*
+ * Returns the host name of the server requesting the certificate.
+ */
+ public String getHost();
+
+ /*
+ * Returns the acceptable types of asymmetric keys (can be null).
+ */
+ public String[] getKeyTypes();
+
+ /*
+ * Returns the port number of the server requesting the certificate.
+ */
+ public int getPort();
+
+ /*
+ * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
+ */
+ public Principal[] getPrincipals();
+
+ /*
+ * Ignore the request for now. Do not remember user's choice.
+ */
+ public void ignore();
+
+ /*
+ * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
+ *
+ * @param privateKey The privateKey
+ * @param chain The certificate chain
+ */
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+}
\ No newline at end of file
diff --git a/framework/src/org/apache/cordova/ICordovaHttpAuthHandler.java b/framework/src/org/apache/cordova/ICordovaHttpAuthHandler.java
new file mode 100644
index 0000000000..c55818ac6d
--- /dev/null
+++ b/framework/src/org/apache/cordova/ICordovaHttpAuthHandler.java
@@ -0,0 +1,38 @@
+/*
+ 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.
+*/
+package org.apache.cordova;
+
+/**
+ * Specifies interface for HTTP auth handler object which is used to handle auth requests and
+ * specifying user credentials.
+ */
+ public interface ICordovaHttpAuthHandler {
+ /**
+ * Instructs the WebView to cancel the authentication request.
+ */
+ public void cancel ();
+
+ /**
+ * Instructs the WebView to proceed with the authentication with the given credentials.
+ *
+ * @param username The user name
+ * @param password The password
+ */
+ public void proceed (String username, String password);
+}
\ No newline at end of file
diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java
index 7ddf300599..2fb6b2b896 100755
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@ -242,6 +242,46 @@ public void onPause(boolean multitasking) {
}
}
+ /**
+ * Called when the system received an HTTP authentication request. Plugins can use
+ * the supplied HttpAuthHandler to process this auth challenge.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param handler The HttpAuthHandler used to set the WebView's response
+ * @param host The host requiring authentication
+ * @param realm The realm for which authentication is required
+ *
+ * @return Returns True if there is a plugin which will resolve this auth challenge, otherwise False
+ *
+ */
+ public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
+ for (CordovaPlugin plugin : this.pluginMap.values()) {
+ if (plugin != null && plugin.onReceivedHttpAuthRequest(view, handler, host, realm)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called when he system received an SSL client certificate request. Plugin can use
+ * the supplied ClientCertRequest to process this certificate challenge.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param request The client certificate request
+ *
+ * @return Returns True if plugin will resolve this auth challenge, otherwise False
+ *
+ */
+ public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
+ for (CordovaPlugin plugin : this.pluginMap.values()) {
+ if (plugin != null && plugin.onReceivedClientCertRequest(view, request)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Called when the activity will start interacting with the user.
*
diff --git a/framework/src/org/apache/cordova/SplashScreenInternal.java b/framework/src/org/apache/cordova/SplashScreenInternal.java
index 715e418275..e1154a53fc 100644
--- a/framework/src/org/apache/cordova/SplashScreenInternal.java
+++ b/framework/src/org/apache/cordova/SplashScreenInternal.java
@@ -63,7 +63,7 @@ protected void pluginInitialize() {
firstShow = false;
loadSpinner();
- showSplashScreen();
+ showSplashScreen(true);
}
@Override
@@ -115,7 +115,7 @@ public Object onMessage(String id, Object data) {
if ("hide".equals(data.toString())) {
this.removeSplashScreen();
} else {
- this.showSplashScreen();
+ this.showSplashScreen(false);
}
} else if ("spinner".equals(id)) {
if ("stop".equals(data.toString())) {
@@ -143,7 +143,7 @@ public void run() {
* Shows the splash screen over the full Activity
*/
@SuppressWarnings("deprecation")
- private void showSplashScreen() {
+ private void showSplashScreen(final boolean hideAfterDelay) {
final int splashscreenTime = preferences.getInteger("SplashScreenDelay", 3000);
final int drawableId = preferences.getInteger("SplashDrawableId", 0);
@@ -151,7 +151,7 @@ private void showSplashScreen() {
if (this.splashDialog != null && splashDialog.isShowing()) {
return;
}
- if (drawableId == 0 || splashscreenTime <= 0) {
+ if (drawableId == 0 || (splashscreenTime <= 0 && hideAfterDelay)) {
return;
}
@@ -187,12 +187,14 @@ public void run() {
splashDialog.show();
// Set Runnable to remove splash screen just in case
- final Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- public void run() {
- removeSplashScreen();
- }
- }, splashscreenTime);
+ if (hideAfterDelay) {
+ final Handler handler = new Handler();
+ handler.postDelayed(new Runnable() {
+ public void run() {
+ removeSplashScreen();
+ }
+ }, splashscreenTime);
+ }
}
});
}
diff --git a/package.json b/package.json
index a152ceb696..a2d7722cdc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cordova-android",
- "version": "3.7.0-dev",
+ "version": "3.7.2",
"description": "cordova-android release",
"main": "bin/create",
"repository": {
@@ -26,4 +26,4 @@
"jasmine-node": "~1",
"promise-matchers": "~0"
}
-}
\ No newline at end of file
+}