diff options
Diffstat (limited to 'StoneIsland/platforms/android/CordovaLib')
37 files changed, 644 insertions, 177 deletions
diff --git a/StoneIsland/platforms/android/CordovaLib/build.gradle b/StoneIsland/platforms/android/CordovaLib/build.gradle index 2565633f..b580e13f 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/build.gradle +++ b/StoneIsland/platforms/android/CordovaLib/build.gradle @@ -21,28 +21,22 @@ buildscript { repositories { mavenCentral() + jcenter(); } - // 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+' - } + dependencies { + classpath 'com.android.tools.build:gradle:2.2.1' } + } -apply plugin: 'android-library' +apply plugin: 'com.android.library' + +ext { + apply from: 'cordova.gradle' + cdvCompileSdkVersion = privateHelpers.getProjectTarget() + cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools() +} android { compileSdkVersion cdvCompileSdkVersion diff --git a/StoneIsland/platforms/android/CordovaLib/cordova.gradle b/StoneIsland/platforms/android/CordovaLib/cordova.gradle index 6e89c4c2..21a01bb5 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/cordova.gradle +++ b/StoneIsland/platforms/android/CordovaLib/cordova.gradle @@ -61,7 +61,7 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersion) { highestBuildToolsVersion } else { throw new RuntimeException( - "No installed build tools found. Please install the Android build tools version " + + "No installed build tools found. Install the Android build tools version " + minBuildToolsVersion + " or higher.") } } @@ -125,7 +125,15 @@ def doExtractIntFromManifest(name) { def pattern = Pattern.compile(name + "=\"(\\d+)\"") def matcher = pattern.matcher(manifestFile.getText()) matcher.find() - return Integer.parseInt(matcher.group(1)) + return new BigInteger(matcher.group(1)) +} + +def doExtractStringFromManifest(name) { + def manifestFile = file(android.sourceSets.main.manifest.srcFile) + def pattern = Pattern.compile(name + "=\"(\\S+)\"") + def matcher = pattern.matcher(manifestFile.getText()) + matcher.find() + return matcher.group(1) } def doPromptForPassword(msg) { @@ -179,6 +187,7 @@ ext { privateHelpers.getProjectTarget = { doGetProjectTarget() } privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') } privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) } + privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) } privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) } privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) } diff --git a/StoneIsland/platforms/android/CordovaLib/project.properties b/StoneIsland/platforms/android/CordovaLib/project.properties index 40ae82c1..df3c73c4 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/project.properties +++ b/StoneIsland/platforms/android/CordovaLib/project.properties @@ -10,7 +10,7 @@ # Indicates whether an apk should be generated for each density. split.density=false # Project target. -target=android-22 +target=android-25 apk-configurations= renderscript.opt.level=O0 android.library=true diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java index d3a231a0..d3a231a0 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java index 446c37d9..43363869 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java @@ -20,8 +20,6 @@ package org.apache.cordova; import org.json.JSONArray; -import android.util.Log; - import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginResult; import org.json.JSONObject; @@ -31,22 +29,22 @@ public class CallbackContext { private String callbackId; private CordovaWebView webView; - private boolean finished; + protected boolean finished; private int changingThreads; public CallbackContext(String callbackId, CordovaWebView webView) { this.callbackId = callbackId; this.webView = webView; } - + public boolean isFinished() { return finished; } - + public boolean isChangingThreads() { return changingThreads > 0; } - + public String getCallbackId() { return callbackId; } @@ -54,7 +52,7 @@ public class CallbackContext { public void sendPluginResult(PluginResult pluginResult) { synchronized (this) { if (finished) { - Log.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage()); + LOG.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage()); return; } else { finished = !pluginResult.getKeepCallback(); @@ -98,7 +96,7 @@ public class CallbackContext { public void success(byte[] message) { sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); } - + /** * Helper for success callbacks that just returns the Status.OK by default * diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java new file mode 100644 index 00000000..050daa01 --- /dev/null +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java @@ -0,0 +1,65 @@ +/* + 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.util.Pair; +import android.util.SparseArray; + +/** + * Provides a collection that maps unique request codes to CordovaPlugins and Integers. + * Used to ensure that when plugins make requests for runtime permissions, those requests do not + * collide with requests from other plugins that use the same request code value. + */ +public class CallbackMap { + private int currentCallbackId = 0; + private SparseArray<Pair<CordovaPlugin, Integer>> callbacks; + + public CallbackMap() { + this.callbacks = new SparseArray<Pair<CordovaPlugin, Integer>>(); + } + + /** + * Stores a CordovaPlugin and request code and returns a new unique request code to use + * in a permission request. + * + * @param receiver The plugin that is making the request + * @param requestCode The original request code used by the plugin + * @return A unique request code that can be used to retrieve this callback + * with getAndRemoveCallback() + */ + public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) { + int mappedId = this.currentCallbackId++; + callbacks.put(mappedId, new Pair<CordovaPlugin, Integer>(receiver, requestCode)); + return mappedId; + } + + /** + * Retrieves and removes a callback stored in the map using the mapped request code + * obtained from registerCallback() + * + * @param mappedId The request code obtained from registerCallback() + * @return The CordovaPlugin and orignal request code that correspond to the + * given mappedCode + */ + public synchronized Pair<CordovaPlugin, Integer> getAndRemoveCallback(int mappedId) { + Pair<CordovaPlugin, Integer> callback = callbacks.get(mappedId); + callbacks.remove(mappedId); + return callback; + } +} diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Config.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Config.java index 048960bf..07397959 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Config.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Config.java @@ -22,7 +22,6 @@ package org.apache.cordova; import java.util.List; import android.app.Activity; -import android.util.Log; @Deprecated // Use Whitelist, CordovaPrefences, etc. directly. public class Config { @@ -61,7 +60,7 @@ public class Config { public static List<PluginEntry> getPluginEntries() { return parser.getPluginEntries(); } - + public static CordovaPreferences getPreferences() { return parser.getPreferences(); } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java index 01a97f2d..01a97f2d 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java index 5c3bc508..85eeb53a 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java @@ -26,6 +26,7 @@ import org.json.JSONObject; import android.app.Activity; import android.app.AlertDialog; +import android.annotation.SuppressLint; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; @@ -33,7 +34,6 @@ import android.graphics.Color; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -49,7 +49,7 @@ import android.widget.FrameLayout; * html file that contains the application. * * As an example: - * + * * <pre> * package org.apache.cordova.examples; * @@ -66,8 +66,8 @@ import android.widget.FrameLayout; * } * } * </pre> - * - * Cordova xml configuration: Cordova uses a configuration file at + * + * Cordova xml configuration: Cordova uses a configuration file at * res/xml/config.xml to specify its settings. See "The config.xml File" * guide in cordova-docs at http://cordova.apache.org/docs for the documentation * for the configuration. The use of the set*Property() methods is @@ -103,31 +103,31 @@ public class CordovaActivity extends Activity { */ @Override public void onCreate(Bundle savedInstanceState) { + // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception + loadConfig(); + + String logLevel = preferences.getString("loglevel", "ERROR"); + LOG.setLogLevel(logLevel); + 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)) - { + 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."); + 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."); preferences.set("Fullscreen", true); } - if(preferences.getBoolean("Fullscreen", false)) - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) - { + if (preferences.getBoolean("Fullscreen", false)) { + // NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen + // (as was the case in previous cordova versions) + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) && !preferences.getBoolean("FullscreenNotImmersive", false)) { immersiveMode = true; - } - else - { + } else { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); + WindowManager.LayoutParams.FLAG_FULLSCREEN); } } else { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, @@ -137,12 +137,11 @@ public class CordovaActivity extends Activity { super.onCreate(savedInstanceState); cordovaInterface = makeCordovaInterface(); - if(savedInstanceState != null) - { + if (savedInstanceState != null) { cordovaInterface.restoreInstanceState(savedInstanceState); } } - + protected void init() { appView = makeWebView(); createViews(); @@ -181,9 +180,14 @@ public class CordovaActivity extends Activity { setContentView(appView.getView()); if (preferences.contains("BackgroundColor")) { - int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK); - // Background of activity: - appView.getView().setBackgroundColor(backgroundColor); + try { + int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK); + // Background of activity: + appView.getView().setBackgroundColor(backgroundColor); + } + catch (NumberFormatException e){ + e.printStackTrace(); + } } appView.getView().requestFocusFromTouch(); @@ -191,7 +195,7 @@ public class CordovaActivity extends Activity { /** * Construct the default web view object. - * + * <p/> * Override this to customize the webview that is used. */ protected CordovaWebView makeWebView() { @@ -244,13 +248,13 @@ public class CordovaActivity extends Activity { /** * Called when the activity receives a new intent - **/ + */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); //Forward to plugins if (this.appView != null) - this.appView.onNewIntent(intent); + this.appView.onNewIntent(intent); } /** @@ -260,7 +264,7 @@ public class CordovaActivity extends Activity { protected void onResume() { super.onResume(); LOG.d(TAG, "Resumed the activity."); - + if (this.appView == null) { return; } @@ -320,16 +324,17 @@ public class CordovaActivity extends Activity { super.onWindowFocusChanged(hasFocus); if (hasFocus && immersiveMode) { final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(uiOptions); } } + @SuppressLint("NewApi") @Override public void startActivityForResult(Intent intent, int requestCode, Bundle options) { // Capture requestCode here so that it is captured in the setActivityResultCallback() case. @@ -341,10 +346,10 @@ public class CordovaActivity extends Activity { * Called when an activity you launched exits, giving you the requestCode you started it with, * the resultCode it returned, and any additional data from it. * - * @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 intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). + * @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 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) { @@ -357,9 +362,9 @@ public class CordovaActivity extends Activity { * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). * The errorCode parameter corresponds to one of the ERROR_* constants. * - * @param errorCode The error code corresponding to an ERROR_* value. - * @param description A String describing the error. - * @param failingUrl The url that failed to load. + * @param errorCode The error code corresponding to an ERROR_* value. + * @param description A String describing the error. + * @param failingUrl The url that failed to load. */ public void onReceivedError(final int errorCode, final String description, final String failingUrl) { final CordovaActivity me = this; @@ -448,9 +453,9 @@ public class CordovaActivity extends Activity { /** * Called when a message is sent to plugin. * - * @param id The message id - * @param data The message data - * @return Object or null + * @param id The message id + * @param data The message data + * @return Object or null */ public Object onMessage(String id, Object data) { if ("onReceivedError".equals(id)) { @@ -466,8 +471,7 @@ public class CordovaActivity extends Activity { return null; } - protected void onSaveInstanceState(Bundle outState) - { + protected void onSaveInstanceState(Bundle outState) { cordovaInterface.onSaveInstanceState(outState); super.onSaveInstanceState(outState); } @@ -475,7 +479,7 @@ public class CordovaActivity extends Activity { /** * Called by the system when the device configuration changes while your activity is running. * - * @param newConfig The new device configuration + * @param newConfig The new device configuration */ @Override public void onConfigurationChanged(Configuration newConfig) { @@ -488,4 +492,27 @@ public class CordovaActivity extends Activity { pm.onConfigurationChanged(newConfig); } } + + /** + * Called by the system when the user grants permissions + * + * @param requestCode + * @param permissions + * @param grantResults + */ + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], + int[] grantResults) { + try + { + cordovaInterface.onRequestPermissionResult(requestCode, permissions, grantResults); + } + catch (JSONException e) + { + LOG.d(TAG, "JSONException: Parameters fed into the method are not valid"); + e.printStackTrace(); + } + + } + } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java index d40d26eb..d40d26eb 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java index 7bc4a552..9459a113 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java @@ -23,8 +23,6 @@ import java.security.SecureRandom; import org.json.JSONArray; import org.json.JSONException; -import android.util.Log; - /** * Contains APIs that the JS can call. All functions in here should also have * an equivalent entry in CordovaChromeClient.java, and be added to @@ -87,15 +85,15 @@ public class CordovaBridge { private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException { if (!jsMessageQueue.isBridgeEnabled()) { if (bridgeSecret == -1) { - Log.d(LOG_TAG, action + " call made before bridge was enabled."); + LOG.d(LOG_TAG, action + " call made before bridge was enabled."); } else { - Log.d(LOG_TAG, "Ignoring " + action + " from previous page load."); + LOG.d(LOG_TAG, "Ignoring " + action + " from previous page load."); } return false; } // Bridge secret wrong and bridge not due to it being from the previous page. if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) { - Log.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!"); + LOG.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!"); clearBridgeSecret(); throw new IllegalAccessException(); } @@ -120,7 +118,7 @@ public class CordovaBridge { public void reset() { jsMessageQueue.reset(); - clearBridgeSecret(); + clearBridgeSecret(); } public String promptOnJsPrompt(String origin, String message, String defaultValue) { @@ -141,7 +139,7 @@ public class CordovaBridge { } return ""; } - // Sets the native->JS bridge mode. + // Sets the native->JS bridge mode. else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) { try { int bridgeSecret = Integer.parseInt(defaultValue.substring(16)); @@ -153,7 +151,7 @@ public class CordovaBridge { } return ""; } - // Polling for JavaScript messages + // Polling for JavaScript messages else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) { int bridgeSecret = Integer.parseInt(defaultValue.substring(9)); try { @@ -175,7 +173,7 @@ public class CordovaBridge { int secret = generateBridgeSecret(); return ""+secret; } else { - Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin); + LOG.e(LOG_TAG, "gap_init called from restricted origin: " + origin); } return ""; } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java index 5dd0ecae..5dd0ecae 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java index a219c992..a219c992 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java index 724381e2..724381e2 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java index 59ed4864..3b8468f3 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java @@ -69,4 +69,20 @@ public interface CordovaInterface { * Returns a shared thread pool that can be used for background tasks. */ public ExecutorService getThreadPool(); + + /** + * Sends a permission request to the activity for one permission. + */ + public void requestPermission(CordovaPlugin plugin, int requestCode, String permission); + + /** + * Sends a permission request to the activity for a group of permissions + */ + public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions); + + /** + * Check for a permission. Returns true if the permission is granted, false otherwise. + */ + public boolean hasPermission(String permission); + } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java index e35a181d..71dcb782 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java @@ -21,8 +21,13 @@ package org.apache.cordova; import android.app.Activity; import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; -import android.util.Log; +import android.util.Pair; + +import org.json.JSONException; +import org.json.JSONObject; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -37,9 +42,12 @@ public class CordovaInterfaceImpl implements CordovaInterface { protected PluginManager pluginManager; protected ActivityResultHolder savedResult; + protected CallbackMap permissionResultCallbacks; protected CordovaPlugin activityResultCallback; protected String initCallbackService; protected int activityResultRequestCode; + protected boolean activityWasDestroyed = false; + protected Bundle savedPluginState; public CordovaInterfaceImpl(Activity activity) { this(activity, Executors.newCachedThreadPool()); @@ -48,6 +56,7 @@ public class CordovaInterfaceImpl implements CordovaInterface { public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) { this.activity = activity; this.threadPool = threadPool; + this.permissionResultCallbacks = new CallbackMap(); } @Override @@ -89,12 +98,31 @@ public class CordovaInterfaceImpl implements CordovaInterface { } /** - * Dispatches any pending onActivityResult callbacks. + * Dispatches any pending onActivityResult callbacks and sends the resume event if the + * Activity was destroyed by the OS. */ public void onCordovaInit(PluginManager pluginManager) { this.pluginManager = pluginManager; if (savedResult != null) { onActivityResult(savedResult.requestCode, savedResult.resultCode, savedResult.intent); + } else if(activityWasDestroyed) { + // If there was no Activity result, we still need to send out the resume event if the + // Activity was destroyed by the OS + activityWasDestroyed = false; + if(pluginManager != null) + { + CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME); + if(appPlugin != null) { + JSONObject obj = new JSONObject(); + try { + obj.put("action", "resume"); + } catch (JSONException e) { + LOG.e(TAG, "Failed to create event message", e); + } + appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, obj)); + } + } + } } @@ -109,18 +137,22 @@ public class CordovaInterfaceImpl implements CordovaInterface { savedResult = new ActivityResultHolder(requestCode, resultCode, intent); if (pluginManager != null) { callback = pluginManager.getPlugin(initCallbackService); + if(callback != null) { + callback.onRestoreStateForActivityResult(savedPluginState.getBundle(callback.getServiceName()), + new ResumeCallback(callback.getServiceName(), pluginManager)); + } } } activityResultCallback = null; if (callback != null) { - Log.d(TAG, "Sending activity result to plugin"); + LOG.d(TAG, "Sending activity result to plugin"); initCallbackService = null; savedResult = null; callback.onActivityResult(requestCode, resultCode, intent); return true; } - Log.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!": ".")); + LOG.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!" : ".")); return false; } @@ -141,6 +173,10 @@ public class CordovaInterfaceImpl implements CordovaInterface { String serviceName = activityResultCallback.getServiceName(); outState.putString("callbackService", serviceName); } + if(pluginManager != null){ + outState.putBundle("plugin", pluginManager.onSaveInstanceState()); + } + } /** @@ -148,6 +184,8 @@ public class CordovaInterfaceImpl implements CordovaInterface { */ public void restoreInstanceState(Bundle savedInstanceState) { initCallbackService = savedInstanceState.getString("callbackService"); + savedPluginState = savedInstanceState.getBundle("plugin"); + activityWasDestroyed = true; } private static class ActivityResultHolder { @@ -161,4 +199,43 @@ public class CordovaInterfaceImpl implements CordovaInterface { this.intent = intent; } } + + /** + * Called by the system when the user grants permissions + * + * @param requestCode + * @param permissions + * @param grantResults + */ + public void onRequestPermissionResult(int requestCode, String[] permissions, + int[] grantResults) throws JSONException { + Pair<CordovaPlugin, Integer> callback = permissionResultCallbacks.getAndRemoveCallback(requestCode); + if(callback != null) { + callback.first.onRequestPermissionResult(callback.second, permissions, grantResults); + } + } + + public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) { + String[] permissions = new String [1]; + permissions[0] = permission; + requestPermissions(plugin, requestCode, permissions); + } + + public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) { + int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode); + getActivity().requestPermissions(permissions, mappedRequestCode); + } + + public boolean hasPermission(String permission) + { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + { + int result = activity.checkSelfPermission(permission); + return PackageManager.PERMISSION_GRANTED == result; + } + else + { + return true; + } + } } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java index 7cf8528f..41af1db7 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java @@ -26,8 +26,11 @@ import org.json.JSONArray; import org.json.JSONException; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.net.Uri; +import android.os.Build; +import android.os.Bundle; import java.io.FileNotFoundException; import java.io.IOException; @@ -75,7 +78,7 @@ public class CordovaPlugin { public String getServiceName() { return serviceName; } - + /** * Executes the request. * @@ -173,6 +176,29 @@ public class CordovaPlugin { } /** + * Called when the Activity is being destroyed (e.g. if a plugin calls out to an external + * Activity and the OS kills the CordovaActivity in the background). The plugin should save its + * state in this method only if it is awaiting the result of an external Activity and needs + * to preserve some information so as to handle that result; onRestoreStateForActivityResult() + * will only be called if the plugin is the recipient of an Activity result + * + * @return Bundle containing the state of the plugin or null if state does not need to be saved + */ + public Bundle onSaveInstanceState() { + return null; + } + + /** + * Called when a plugin is the recipient of an Activity result after the CordovaActivity has + * been destroyed. The Bundle will be the same as the one the plugin returned in + * onSaveInstanceState() + * + * @param state Bundle containing the state of the plugin + * @param callbackContext Replacement Context to return the plugin result to + */ + public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {} + + /** * Called when a message is sent to plugin. * * @param id The message id @@ -321,7 +347,7 @@ public class CordovaPlugin { */ public void onReset() { } - + /** * Called when the system received an HTTP authentication request. Plugin can use * the supplied HttpAuthHandler to process this auth challenge. @@ -330,14 +356,14 @@ public class CordovaPlugin { * @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. @@ -359,4 +385,38 @@ public class CordovaPlugin { */ public void onConfigurationChanged(Configuration newConfig) { } + + /** + * Called by the Plugin Manager when we need to actually request permissions + * + * @param requestCode Passed to the activity to track the request + * + * @return Returns the permission that was stored in the plugin + */ + + public void requestPermissions(int requestCode) { + } + + /* + * Called by the WebView implementation to check for geolocation permissions, can be used + * by other Java methods in the event that a plugin is using this as a dependency. + * + * @return Returns true if the plugin has all the permissions it needs to operate. + */ + + public boolean hasPermisssion() { + return true; + } + + /** + * Called by the system when the user grants permissions + * + * @param requestCode + * @param permissions + * @param grantResults + */ + public void onRequestPermissionResult(int requestCode, String[] permissions, + int[] grantResults) throws JSONException { + + } } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java index 4dbc93e6..4dbc93e6 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java index e725e255..e725e255 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java index ba58f9a0..2eebd0d3 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java @@ -31,7 +31,7 @@ import android.webkit.WebChromeClient.CustomViewCallback; * are not expected to implement it. */ public interface CordovaWebView { - public static final String CORDOVA_VERSION = "4.1.1"; + public static final String CORDOVA_VERSION = "6.1.2"; void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences); diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java index dd84ab11..c8e5a55d 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java @@ -20,9 +20,10 @@ package org.apache.cordova; import android.view.KeyEvent; import android.view.View; +import android.webkit.ValueCallback; /** - * Interfcae for all Cordova engines. + * Interface for all Cordova engines. * No methods will be added to this class (in order to be compatible with existing engines). * Instead, we will create a new interface: e.g. CordovaWebViewEngineV2 */ @@ -58,6 +59,9 @@ public interface CordovaWebViewEngine { /** Clean up all resources associated with the WebView. */ void destroy(); + /** Add the evaulate Javascript method **/ + void evaluateJavascript(String js, ValueCallback<String> callback); + /** * Used to retrieve the associated CordovaWebView given a View without knowing the type of Engine. * E.g. ((CordovaWebView.EngineView)activity.findViewById(android.R.id.webView)).getCordovaWebView(); diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java index 06da55e1..85a0b5f5 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java @@ -21,7 +21,6 @@ package org.apache.cordova; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; @@ -135,6 +134,7 @@ public class CordovaWebViewImpl implements CordovaWebView { if (recreatePlugins) { // Don't re-initialize on first load. if (loadedUrl != null) { + appPlugin = null; pluginManager.init(); } loadedUrl = url; @@ -244,7 +244,7 @@ public class CordovaWebViewImpl implements CordovaWebView { @Deprecated public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) { // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0 - Log.d(TAG, "showing Custom View"); + LOG.d(TAG, "showing Custom View"); // if a view already exists then immediately terminate the new one if (mCustomView != null) { callback.onCustomViewHidden(); @@ -275,7 +275,7 @@ public class CordovaWebViewImpl implements CordovaWebView { public void hideCustomView() { // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0 if (mCustomView == null) return; - Log.d(TAG, "Hiding Custom View"); + LOG.d(TAG, "Hiding Custom View"); // Hide the custom view. mCustomView.setVisibility(View.GONE); @@ -354,6 +354,7 @@ public class CordovaWebViewImpl implements CordovaWebView { case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_MENU: // TODO: Why are search and menu buttons handled separately? if (override) { boundKeyCodes.add(keyCode); @@ -445,7 +446,10 @@ public class CordovaWebViewImpl implements CordovaWebView { // Resume JavaScript timers. This affects all webviews within the app! engine.setPaused(false); this.pluginManager.onResume(keepRunning); - // To be the same as other platforms, fire this event only when resumed after a "pause". + + // In order to match the behavior of the other platforms, we only send onResume after an + // onPause has occurred. The resume event might still be sent if the Activity was killed + // while waiting for the result of an external Activity once the result is obtained if (hasPausedEver) { sendJavascriptEvent("resume"); } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java index 000717a2..e384f8d7 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java @@ -19,10 +19,6 @@ package org.apache.cordova; -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.LOG; -import org.apache.cordova.PluginResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -34,17 +30,20 @@ import android.content.IntentFilter; import android.telephony.TelephonyManager; import android.view.KeyEvent; +import java.lang.reflect.Field; import java.util.HashMap; /** * This class exposes methods in Cordova that can be called from JavaScript. */ -class CoreAndroid extends CordovaPlugin { +public class CoreAndroid extends CordovaPlugin { public static final String PLUGIN_NAME = "CoreAndroid"; protected static final String TAG = "CordovaApp"; private BroadcastReceiver telephonyReceiver; private CallbackContext messageChannel; + private PluginResult pendingResume; + private final Object messageChannelLock = new Object(); /** * Send an event to be fired on the Javascript side. @@ -112,7 +111,13 @@ class CoreAndroid extends CordovaPlugin { this.exitApp(); } else if (action.equals("messageChannel")) { - messageChannel = callbackContext; + synchronized(messageChannelLock) { + messageChannel = callbackContext; + if (pendingResume != null) { + sendEventMessage(pendingResume); + pendingResume = null; + } + } return true; } @@ -248,6 +253,9 @@ class CoreAndroid extends CordovaPlugin { else if (button.equals("volumedown")) { webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override); } + else if (button.equals("menubutton")) { + webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override); + } } /** @@ -313,10 +321,13 @@ class CoreAndroid extends CordovaPlugin { } catch (JSONException e) { LOG.e(TAG, "Failed to create event message", e); } - PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, obj); - pluginResult.setKeepCallback(true); + sendEventMessage(new PluginResult(PluginResult.Status.OK, obj)); + } + + private void sendEventMessage(PluginResult payload) { + payload.setKeepCallback(true); if (messageChannel != null) { - messageChannel.sendPluginResult(pluginResult); + messageChannel.sendPluginResult(payload); } } @@ -328,4 +339,52 @@ class CoreAndroid extends CordovaPlugin { { webView.getContext().unregisterReceiver(this.telephonyReceiver); } + + /** + * Used to send the resume event in the case that the Activity is destroyed by the OS + * + * @param resumeEvent PluginResult containing the payload for the resume event to be fired + */ + public void sendResumeEvent(PluginResult resumeEvent) { + // This operation must be synchronized because plugin results that trigger resume + // events can be processed asynchronously + synchronized(messageChannelLock) { + if (messageChannel != null) { + sendEventMessage(resumeEvent); + } else { + // Might get called before the page loads, so we need to store it until the + // messageChannel gets created + this.pendingResume = resumeEvent; + } + } + } + + /* + * This needs to be implemented if you wish to use the Camera Plugin or other plugins + * that read the Build Configuration. + * + * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to + * StackOverflow. This is annoying as hell! + * + */ + + public static Object getBuildConfigValue(Context ctx, String key) + { + try + { + Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig"); + Field field = clazz.getField(key); + return field.get(null); + } catch (ClassNotFoundException e) { + LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?"); + e.printStackTrace(); + } catch (NoSuchFieldException e) { + LOG.d(TAG, key + " is not a valid field. Check your build.gradle"); + } catch (IllegalAccessException e) { + LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace."); + e.printStackTrace(); + } + + return null; + } } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java index acc65c6f..acc65c6f 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java index 455d2f9d..455d2f9d 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java index e776194f..e776194f 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java index c55818ac..c55818ac 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java index 3dd1a754..9fe7a7df 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/LOG.java @@ -158,6 +158,16 @@ public class LOG { * Warning log message. * * @param tag + * @param e + */ + public static void w(String tag, Throwable e) { + if (LOG.WARN >= LOGLEVEL) Log.w(tag, e); + } + + /** + * Warning log message. + * + * @param tag * @param s * @param e */ diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java index a05e8b81..61d04f17 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java @@ -21,8 +21,6 @@ package org.apache.cordova; import java.util.ArrayList; import java.util.LinkedList; -import android.util.Log; - /** * Holds the list of messages to be sent to the WebView. */ @@ -42,13 +40,13 @@ public class NativeToJsMessageQueue { // This currently only chops up on message boundaries. It may be useful // to allow it to break up messages. private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240; - + /** * When true, the active listener is not fired upon enqueue. When set to false, - * the active listener will be fired if the queue is non-empty. + * the active listener will be fired if the queue is non-empty. */ private boolean paused; - + /** * The list of JavaScript statements to be sent to JavaScript. */ @@ -58,7 +56,7 @@ public class NativeToJsMessageQueue { * The array of listeners that can be used to send messages to JS. */ private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>(); - + /** * When null, the bridge is disabled. This occurs during page transitions. * When disabled, all callbacks are dropped since they are assumed to be @@ -83,11 +81,11 @@ public class NativeToJsMessageQueue { */ public void setBridgeMode(int value) { if (value < -1 || value >= bridgeModes.size()) { - Log.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value); + LOG.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value); } else { BridgeMode newMode = value < 0 ? null : bridgeModes.get(value); if (newMode != activeBridgeMode) { - Log.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName())); + LOG.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName())); synchronized (this) { activeBridgeMode = newMode; if (newMode != null) { @@ -100,7 +98,7 @@ public class NativeToJsMessageQueue { } } } - + /** * Clears all messages and resets to the default bridge mode. */ @@ -114,16 +112,16 @@ public class NativeToJsMessageQueue { private int calculatePackedMessageLength(JsMessage message) { int messageLen = message.calculateEncodedLength(); String messageLenStr = String.valueOf(messageLen); - return messageLenStr.length() + messageLen + 1; + return messageLenStr.length() + messageLen + 1; } - + private void packMessage(JsMessage message, StringBuilder sb) { int len = message.calculateEncodedLength(); sb.append(len) .append(' '); message.encodeAsMessage(sb); } - + /** * Combines and returns queued messages combined into a single string. * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE. @@ -154,7 +152,7 @@ public class NativeToJsMessageQueue { JsMessage message = queue.removeFirst(); packMessage(message, sb); } - + if (!queue.isEmpty()) { // Attach a char to indicate that there are more messages pending. sb.append('*'); @@ -163,7 +161,7 @@ public class NativeToJsMessageQueue { return ret; } } - + /** * Same as popAndEncode(), except encodes in a form that can be executed as JS. */ @@ -185,7 +183,7 @@ public class NativeToJsMessageQueue { } boolean willSendAllMessages = numMessagesToSend == queue.size(); StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100)); - // Wrap each statement in a try/finally so that if one throws it does + // Wrap each statement in a try/finally so that if one throws it does // not affect the next. for (int i = 0; i < numMessagesToSend; ++i) { JsMessage message = queue.removeFirst(); @@ -206,7 +204,7 @@ public class NativeToJsMessageQueue { String ret = sb.toString(); return ret; } - } + } /** * Add a JavaScript statement to the list. @@ -220,7 +218,7 @@ public class NativeToJsMessageQueue { */ public void addPluginResult(PluginResult result, String callbackId) { if (callbackId == null) { - Log.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable()); + LOG.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable()); return; } // Don't send anything if there is no result and there is no need to @@ -243,7 +241,7 @@ public class NativeToJsMessageQueue { private void enqueueMessage(JsMessage message) { synchronized (this) { if (activeBridgeMode == null) { - Log.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge"); + LOG.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge"); return; } queue.add(message); @@ -257,7 +255,7 @@ public class NativeToJsMessageQueue { if (paused && value) { // This should never happen. If a use-case for it comes up, we should // change pause to be a counter. - Log.e(LOG_TAG, "nested call to setPaused detected.", new Throwable()); + LOG.e(LOG_TAG, "nested call to setPaused detected.", new Throwable()); } paused = value; if (!value) { @@ -265,7 +263,7 @@ public class NativeToJsMessageQueue { if (!queue.isEmpty() && activeBridgeMode != null) { activeBridgeMode.onNativeToJsMessageAvailable(this); } - } + } } } @@ -351,6 +349,31 @@ public class NativeToJsMessageQueue { } } + /** Uses webView.evaluateJavascript to execute messages. */ + public static class EvalBridgeMode extends BridgeMode { + private final CordovaWebViewEngine engine; + private final CordovaInterface cordova; + + public EvalBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) { + this.engine = engine; + this.cordova = cordova; + } + + @Override + public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + String js = queue.popAndEncodeAsJs(); + if (js != null) { + engine.evaluateJavascript(js, null); + } + } + }); + } + } + + + private static class JsMessage { final String jsPayloadOrCallbackId; final PluginResult pluginResult; @@ -368,7 +391,7 @@ public class NativeToJsMessageQueue { jsPayloadOrCallbackId = callbackId; this.pluginResult = pluginResult; } - + static int calculateEncodedLengthHelper(PluginResult pluginResult) { switch (pluginResult.getMessageType()) { case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t @@ -395,7 +418,7 @@ public class NativeToJsMessageQueue { return pluginResult.getMessage().length(); } } - + int calculateEncodedLength() { if (pluginResult == null) { return jsPayloadOrCallbackId.length() + 1; @@ -424,7 +447,7 @@ public class NativeToJsMessageQueue { case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S sb.append('S'); sb.append(pluginResult.getMessage()); - break; + break; case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A sb.append('A'); sb.append(pluginResult.getMessage()); @@ -443,7 +466,7 @@ public class NativeToJsMessageQueue { sb.append(pluginResult.getMessage()); // [ or { } } - + void encodeAsMessage(StringBuilder sb) { if (pluginResult == null) { sb.append('J') diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java index a541e770..c9576a6c 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java @@ -26,8 +26,8 @@ import org.json.JSONException; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; +import android.os.Bundle; import android.os.Debug; -import android.util.Log; /** * PluginManager is exposed to JavaScript in the Cordova WebView. @@ -47,6 +47,8 @@ public class PluginManager { private final CordovaWebView app; private boolean isInitialized; + private CordovaPlugin permissionRequester; + public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, Collection<PluginEntry> pluginEntries) { this.ctx = cordova; this.app = cordovaWebView; @@ -119,7 +121,7 @@ public class PluginManager { public void exec(final String service, final String action, final String callbackId, final String rawArgs) { CordovaPlugin plugin = getPlugin(service); if (plugin == null) { - Log.d(TAG, "exec() call to unknown plugin: " + service); + LOG.d(TAG, "exec() call to unknown plugin: " + service); PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION); app.sendPluginResult(cr, callbackId); return; @@ -131,7 +133,7 @@ public class PluginManager { long duration = System.currentTimeMillis() - pluginStartTime; if (duration > SLOW_EXEC_WARNING_THRESHOLD) { - Log.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool()."); + LOG.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool()."); } if (!wasValidAction) { PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION); @@ -141,7 +143,7 @@ public class PluginManager { PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); callbackContext.sendPluginResult(cr); } catch (Exception e) { - Log.e(TAG, "Uncaught exception from plugin", e); + LOG.e(TAG, "Uncaught exception from plugin", e); callbackContext.error(e.getMessage()); } } @@ -219,9 +221,9 @@ public class PluginManager { * @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()) { @@ -231,7 +233,7 @@ public class PluginManager { } return false; } - + /** * Called when he system received an SSL client certificate request. Plugin can use * the supplied ClientCertRequest to process this certificate challenge. @@ -508,4 +510,17 @@ public class PluginManager { } } } + + public Bundle onSaveInstanceState() { + Bundle state = new Bundle(); + for (CordovaPlugin plugin : this.pluginMap.values()) { + if (plugin != null) { + Bundle pluginState = plugin.onSaveInstanceState(); + if(pluginState != null) { + state.putBundle(plugin.getServiceName(), pluginState); + } + } + } + return state; + } } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java index 2b3ac72e..2b3ac72e 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java new file mode 100644 index 00000000..49a43b5d --- /dev/null +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java @@ -0,0 +1,76 @@ +/* + 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 org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class ResumeCallback extends CallbackContext { + private final String TAG = "CordovaResumeCallback"; + private String serviceName; + private PluginManager pluginManager; + + public ResumeCallback(String serviceName, PluginManager pluginManager) { + super("resumecallback", null); + this.serviceName = serviceName; + this.pluginManager = pluginManager; + } + + @Override + public void sendPluginResult(PluginResult pluginResult) { + synchronized (this) { + if (finished) { + LOG.w(TAG, serviceName + " attempted to send a second callback to ResumeCallback\nResult was: " + pluginResult.getMessage()); + return; + } else { + finished = true; + } + } + + JSONObject event = new JSONObject(); + JSONObject pluginResultObject = new JSONObject(); + + try { + pluginResultObject.put("pluginServiceName", this.serviceName); + pluginResultObject.put("pluginStatus", PluginResult.StatusMessages[pluginResult.getStatus()]); + + event.put("action", "resume"); + event.put("pendingResult", pluginResultObject); + } catch (JSONException e) { + LOG.e(TAG, "Unable to create resume object for Activity Result"); + } + + PluginResult eventResult = new PluginResult(PluginResult.Status.OK, event); + + // We send a list of results to the js so that we don't have to decode + // the PluginResult passed to this CallbackContext into JSON twice. + // The results are combined into an event payload before the event is + // fired on the js side of things (see platform.js) + List<PluginResult> result = new ArrayList<PluginResult>(); + result.add(eventResult); + result.add(pluginResult); + + CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME); + appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, result)); + } +} diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java index d0f823c3..d0f823c3 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java index ae55dfee..acf795fa 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java @@ -19,6 +19,7 @@ package org.apache.cordova.engine; +import android.annotation.TargetApi; import android.os.Build; import android.webkit.CookieManager; import android.webkit.WebView; @@ -30,10 +31,15 @@ class SystemCookieManager implements ICordovaCookieManager { protected final WebView webView; private final CookieManager cookieManager; + //Added because lint can't see the conditional RIGHT ABOVE this + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SystemCookieManager(WebView webview) { webView = webview; cookieManager = CookieManager.getInstance(); + //REALLY? Nobody has seen this UNTIL NOW? + cookieManager.setAcceptFileSchemeCookies(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.setAcceptThirdPartyCookies(webView, true); } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java index 3b5866c3..3ea5e576 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java @@ -21,11 +21,11 @@ package org.apache.cordova.engine; import java.util.Arrays; import android.annotation.TargetApi; import android.app.Activity; +import android.content.Context; import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Build; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -61,15 +61,17 @@ public class SystemWebChromeClient extends WebChromeClient { // the video progress view private View mVideoProgressView; - + private CordovaDialogsHelper dialogsHelper; + private Context appContext; private WebChromeClient.CustomViewCallback mCustomViewCallback; private View mCustomView; public SystemWebChromeClient(SystemWebViewEngine parentEngine) { this.parentEngine = parentEngine; - dialogsHelper = new CordovaDialogsHelper(parentEngine.webView.getContext()); + appContext = parentEngine.webView.getContext(); + dialogsHelper = new CordovaDialogsHelper(appContext); } /** @@ -174,14 +176,23 @@ public class SystemWebChromeClient extends WebChromeClient { /** * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. * + * This also checks for the Geolocation Plugin and requests permission from the application to use Geolocation. + * * @param origin * @param callback */ public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { super.onGeolocationPermissionsShowPrompt(origin, callback); callback.invoke(origin, true, false); + //Get the plugin, it should be loaded + CordovaPlugin geolocation = parentEngine.pluginManager.getPlugin("Geolocation"); + if(geolocation != null && !geolocation.hasPermisssion()) + { + geolocation.requestPermissions(0); + } + } - + // API level 7 is required for this, see if we could lower this using something else @Override public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { @@ -201,9 +212,9 @@ public class SystemWebChromeClient extends WebChromeClient { */ public View getVideoLoadingProgressView() { - if (mVideoProgressView == null) { + if (mVideoProgressView == null) { // Create a new Loading view programmatically. - + // create the linear layout LinearLayout layout = new LinearLayout(parentEngine.getView().getContext()); layout.setOrientation(LinearLayout.VERTICAL); @@ -214,12 +225,12 @@ public class SystemWebChromeClient extends WebChromeClient { ProgressBar bar = new ProgressBar(parentEngine.getView().getContext()); LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); barLayoutParams.gravity = Gravity.CENTER; - bar.setLayoutParams(barLayoutParams); + bar.setLayoutParams(barLayoutParams); layout.addView(bar); - + mVideoProgressView = layout; } - return mVideoProgressView; + return mVideoProgressView; } // <input type=file> support: @@ -228,11 +239,11 @@ public class SystemWebChromeClient extends WebChromeClient { public void openFileChooser(ValueCallback<Uri> uploadMsg) { this.openFileChooser(uploadMsg, "*/*"); } - + public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) { this.openFileChooser(uploadMsg, acceptType, null); } - + public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptType, String capture) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); @@ -242,7 +253,7 @@ public class SystemWebChromeClient extends WebChromeClient { @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); - Log.d(LOG_TAG, "Receive file chooser URL: " + result); + LOG.d(LOG_TAG, "Receive file chooser URL: " + result); uploadMsg.onReceiveValue(result); } }, intent, FILECHOOSER_RESULTCODE); @@ -257,12 +268,12 @@ public class SystemWebChromeClient extends WebChromeClient { @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent); - Log.d(LOG_TAG, "Receive file chooser URL: " + result); + LOG.d(LOG_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); + LOG.w("No activity found to handle file chooser intent.", e); filePathsCallback.onReceiveValue(null); } return true; @@ -271,7 +282,7 @@ public class SystemWebChromeClient extends WebChromeClient { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onPermissionRequest(final PermissionRequest request) { - Log.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources())); + LOG.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources())); request.grant(request.getResources()); } diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java index 01c2f000..01c2f000 100755..100644 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java diff --git a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java index 221a884c..0fa02767 100755 --- a/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java +++ b/StoneIsland/platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java @@ -27,8 +27,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.os.Build; -import android.util.Log; import android.view.View; +import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebView; @@ -40,6 +40,7 @@ import org.apache.cordova.CordovaResourceApi; import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebViewEngine; import org.apache.cordova.ICordovaCookieManager; +import org.apache.cordova.LOG; import org.apache.cordova.NativeToJsMessageQueue; import org.apache.cordova.PluginManager; @@ -116,7 +117,9 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { SystemWebViewEngine.this.cordova.getActivity().runOnUiThread(r); } })); - bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue); + if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) + nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.EvalBridgeMode(this, cordova)); + bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue); exposeJsInterface(webView, bridge); } @@ -135,7 +138,7 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { return webView; } - @SuppressLint("SetJavaScriptEnabled") + @SuppressLint({"NewApi", "SetJavaScriptEnabled"}) @SuppressWarnings("deprecation") private void initWebViewSettings() { webView.setInitialScale(0); @@ -145,32 +148,32 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL); - + // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2) try { Method gingerbread_getMethod = WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class }); - + String manufacturer = android.os.Build.MANUFACTURER; - Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer); + LOG.d(TAG, "CordovaWebView is running on device made by: " + manufacturer); if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB && android.os.Build.MANUFACTURER.contains("HTC")) { gingerbread_getMethod.invoke(settings, true); } } catch (NoSuchMethodException e) { - Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8"); + LOG.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8"); } catch (IllegalArgumentException e) { - Log.d(TAG, "Doing the NavDump failed with bad arguments"); + LOG.d(TAG, "Doing the NavDump failed with bad arguments"); } catch (IllegalAccessException e) { - Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore"); + LOG.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore"); } catch (InvocationTargetException e) { - Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore."); + LOG.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore."); } //We don't save any form data in the application settings.setSaveFormData(false); settings.setSavePassword(false); - + // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist // while we do this if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { @@ -184,15 +187,15 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabaseEnabled(true); settings.setDatabasePath(databasePath); - - + + //Determine whether we're in debug or release mode, and turn on Debugging! ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo(); if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { enableRemoteDebugging(); } - + settings.setGeolocationDatabasePath(databasePath); // Enable DOM storage @@ -200,13 +203,13 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { // Enable built-in geolocation settings.setGeolocationEnabled(true); - + // Enable AppCache // Fix for CB-2282 settings.setAppCacheMaxSize(5 * 1048576); settings.setAppCachePath(databasePath); settings.setAppCacheEnabled(true); - + // Fix for CB-1405 // Google issue 4641 String defaultUserAgent = settings.getUserAgentString(); @@ -222,7 +225,7 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { } } // End CB-3360 - + IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); if (this.receiver == null) { @@ -242,18 +245,18 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { try { WebView.setWebContentsDebuggingEnabled(true); } catch (IllegalArgumentException e) { - Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); + LOG.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); e.printStackTrace(); } } private static void exposeJsInterface(WebView webView, CordovaBridge bridge) { if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) { - Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); + LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); // Bug being that Java Strings do not get converted to JS strings automatically. // This isn't hard to work-around on the JS side, but it's easier to just // use the prompt bridge instead. - return; + return; } SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge); webView.addJavascriptInterface(exposedJsApi, "_cordovaNative"); @@ -312,8 +315,10 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { @Override public void setPaused(boolean value) { if (value) { + webView.onPause(); webView.pauseTimers(); } else { + webView.onResume(); webView.resumeTimers(); } } @@ -327,8 +332,19 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { try { webView.getContext().unregisterReceiver(receiver); } catch (Exception e) { - Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e); + LOG.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e); } } } + + @Override + public void evaluateJavascript(String js, ValueCallback<String> callback) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(js, callback); + } + else + { + LOG.d(TAG, "This webview is using the old bridge"); + } + } } |
