diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java index 2ff76fee..f648ab89 100755 --- a/framework/src/org/apache/cordova/DroidGap.java +++ b/framework/src/org/apache/cordova/DroidGap.java @@ -22,9 +22,9 @@ import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.apache.cordova.api.Plugin; -import org.apache.cordova.api.LOG; import org.apache.cordova.api.CordovaInterface; +import org.apache.cordova.api.CordovaPlugin; +import org.apache.cordova.api.LOG; import org.json.JSONException; import org.json.JSONObject; @@ -162,7 +162,7 @@ public class DroidGap extends Activity implements CordovaInterface { String baseUrl = null; // Plugin to call when activity result is received - protected Plugin activityResultCallback = null; + protected CordovaPlugin activityResultCallback = null; protected boolean activityResultKeepRunning; // Default background color for activity @@ -773,7 +773,7 @@ public class DroidGap extends Activity implements CordovaInterface { * @param intent The intent to start * @param requestCode The request code that is passed to callback to identify the activity */ - public void startActivityForResult(Plugin command, Intent intent, int requestCode) { + public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) { this.activityResultCallback = command; this.activityResultKeepRunning = this.keepRunning; @@ -798,13 +798,13 @@ public class DroidGap extends Activity implements CordovaInterface { */ protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); - Plugin callback = this.activityResultCallback; + CordovaPlugin callback = this.activityResultCallback; if (callback != null) { callback.onActivityResult(requestCode, resultCode, intent); } } - public void setActivityResultCallback(Plugin plugin) { + public void setActivityResultCallback(CordovaPlugin plugin) { this.activityResultCallback = plugin; } diff --git a/framework/src/org/apache/cordova/Echo.java b/framework/src/org/apache/cordova/Echo.java index 23654c9a..b91c3c43 100644 --- a/framework/src/org/apache/cordova/Echo.java +++ b/framework/src/org/apache/cordova/Echo.java @@ -18,40 +18,27 @@ */ package org.apache.cordova; -import org.apache.cordova.api.Plugin; -import org.apache.cordova.api.PluginResult; +import org.apache.cordova.api.CallbackContext; +import org.apache.cordova.api.CordovaPlugin; import org.json.JSONArray; import org.json.JSONException; -public class Echo extends Plugin { +public class Echo extends CordovaPlugin { - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. - * @param callbackId The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. - */ - public PluginResult execute(String action, JSONArray args, String callbackId) { - try { - String result = args.getString(0); - if ("echo".equals(action) || "echoAsync".equals(action)) { - return new PluginResult(PluginResult.Status.OK, result); - } - return new PluginResult(PluginResult.Status.INVALID_ACTION); - } catch (JSONException e) { - return new PluginResult(PluginResult.Status.JSON_EXCEPTION); + @Override + public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { + final String result = args.getString(0); + if ("echo".equals(action)) { + callbackContext.success(result); + return true; + } else if ("echoAsync".equals(action)) { + cordova.getThreadPool().execute(new Runnable() { + @Override public void run() { + callbackContext.success(result); + } + }); + return true; } - } - - /** - * Identifies if action to be executed returns a value and should be run synchronously. - * - * @param action The action to execute - * @return T=returns value - */ - public boolean isSynch(String action) { - return "echo".equals(action); + return false; } } diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java index 1917d8a7..deee2915 100644 --- a/framework/src/org/apache/cordova/FileTransfer.java +++ b/framework/src/org/apache/cordova/FileTransfer.java @@ -44,7 +44,8 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import org.apache.cordova.api.Plugin; +import org.apache.cordova.api.CallbackContext; +import org.apache.cordova.api.CordovaPlugin; import org.apache.cordova.api.PluginResult; import org.json.JSONArray; import org.json.JSONException; @@ -55,7 +56,7 @@ import android.os.Build; import android.util.Log; import android.webkit.CookieManager; -public class FileTransfer extends Plugin { +public class FileTransfer extends CordovaPlugin { private static final String LOG_TAG = "FileTransfer"; private static final String LINE_START = "--"; @@ -116,7 +117,7 @@ public class FileTransfer extends Plugin { * @see org.apache.cordova.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String) */ @Override - public PluginResult execute(String action, JSONArray args, String callbackId) { + public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { if (action.equals("upload") || action.equals("download")) { String source = null; String target = null; @@ -129,15 +130,18 @@ public class FileTransfer extends Plugin { } if (action.equals("upload")) { - return upload(URLDecoder.decode(source), target, args, callbackId); + upload(URLDecoder.decode(source), target, args, callbackContext); } else { - return download(source, target, args, callbackId); + download(source, target, args, callbackContext); } + return true; } else if (action.equals("abort")) { - return abort(args); - } else { - return new PluginResult(PluginResult.Status.INVALID_ACTION); + String objectId = args.getString(0); + abort(objectId); + callbackContext.success(); + return true; } + return false; } /** @@ -145,7 +149,7 @@ public class FileTransfer extends Plugin { * @param source Full path of the file on the file system * @param target URL of the server to receive the file * @param args JSON Array of args - * @param callbackId callback id for optional progress reports + * @param callbackContext callback id for optional progress reports * * args[2] fileKey Name of file request parameter * args[3] fileName File name to be used on server @@ -153,7 +157,7 @@ public class FileTransfer extends Plugin { * args[5] params key:value pairs of user-defined parameters * @return FileUploadResult containing result of upload request */ - private PluginResult upload(String source, String target, JSONArray args, String callbackId) { + private PluginResult upload(String source, String target, JSONArray args, CallbackContext callbackContext) { Log.d(LOG_TAG, "upload " + source + " to " + target); HttpURLConnection conn = null; @@ -350,7 +354,7 @@ public class FileTransfer extends Plugin { progress.setLoaded(totalBytes); PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject()); progressResult.setKeepCallback(true); - success(progressResult, callbackId); + callbackContext.sendPluginResult(progressResult); } synchronized (abortTriggered) { if (objectId != null && abortTriggered.contains(objectId)) { @@ -536,7 +540,7 @@ public class FileTransfer extends Plugin { * @param target Full path of the file on the file system * @return JSONObject the downloaded file */ - private PluginResult download(String source, String target, JSONArray args, String callbackId) { + private PluginResult download(String source, String target, JSONArray args, CallbackContext callbackContext) { Log.d(LOG_TAG, "download " + source + " to " + target); HttpURLConnection connection = null; @@ -617,7 +621,7 @@ public class FileTransfer extends Plugin { progress.setLoaded(totalBytes); PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject()); progressResult.setKeepCallback(true); - success(progressResult, callbackId); + callbackContext.sendPluginResult(progressResult); } synchronized (abortTriggered) { if (objectId != null && abortTriggered.contains(objectId)) { diff --git a/framework/src/org/apache/cordova/api/CallbackContext.java b/framework/src/org/apache/cordova/api/CallbackContext.java new file mode 100644 index 00000000..c9dc9d7a --- /dev/null +++ b/framework/src/org/apache/cordova/api/CallbackContext.java @@ -0,0 +1,90 @@ +package org.apache.cordova.api; + +import android.util.Log; + +import org.apache.cordova.CordovaWebView; +import org.json.JSONObject; + +public class CallbackContext { + private static final String LOG_TAG = "CordovaPlugin"; + + private String callbackId; + private CordovaWebView webView; + private 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; + } + + 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()); + return; + } else { + finished = !pluginResult.getKeepCallback(); + } + } + webView.sendPluginResult(pluginResult, callbackId); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(JSONObject message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(String message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success() { + sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + + /** + * Helper for error callbacks that just returns the Status.ERROR by default + * + * @param message The message to add to the error result. + */ + public void error(JSONObject message) { + sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message)); + } + + /** + * Helper for error callbacks that just returns the Status.ERROR by default + * + * @param message The message to add to the error result. + * @param callbackId The callback id used when calling back into JavaScript. + */ + public void error(String message) { + sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message)); + } +} \ No newline at end of file diff --git a/framework/src/org/apache/cordova/api/CordovaInterface.java b/framework/src/org/apache/cordova/api/CordovaInterface.java index 40367ca5..6499febe 100755 --- a/framework/src/org/apache/cordova/api/CordovaInterface.java +++ b/framework/src/org/apache/cordova/api/CordovaInterface.java @@ -38,15 +38,14 @@ public interface CordovaInterface { * @param intent The intent to start * @param requestCode The request code that is passed to callback to identify the activity */ - abstract public void startActivityForResult(Plugin command, Intent intent, int requestCode); + abstract public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode); /** * Set the plugin to be called when a sub-activity exits. * * @param plugin The plugin on which onActivityResult is to be called */ - abstract public void setActivityResultCallback(Plugin plugin); - + abstract public void setActivityResultCallback(CordovaPlugin plugin); /** * Get the Android activity. diff --git a/framework/src/org/apache/cordova/api/CordovaPlugin.java b/framework/src/org/apache/cordova/api/CordovaPlugin.java new file mode 100644 index 00000000..8a1da49f --- /dev/null +++ b/framework/src/org/apache/cordova/api/CordovaPlugin.java @@ -0,0 +1,151 @@ +/* + 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.api; + +import org.apache.cordova.CordovaWebView; +import org.json.JSONArray; +import org.json.JSONException; +import android.content.Intent; + + +/** + * Plugins must extend this class and override one of the execute methods. + */ +public class CordovaPlugin { + public String id; + public CordovaWebView webView; // WebView object + public CordovaInterface cordova; + + /** + * @param ctx The context of the main Activity. + */ + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + assert this.cordova == null; + this.cordova = cordova; + this.webView = webView; + } + + /** + * Executes the request. + * + * This method is called from the WebView thread. To do a non-trivial amount of work, use: + * cordova.getThreadPool().execute(runnable); + * + * To run on the UI thread, use: + * cordova.getActivity().runOnUiThread(runnable); + * + * @param action The action to execute. + * @param rawArgs The exec() arguments in JSON form. + * @param callbackId The callback id used when calling back into JavaScript. + * @return Whether the action was valid. + */ + public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException { + JSONArray args = new JSONArray(rawArgs); + return execute(action, args, callbackContext); + } + + /** + * Executes the request. + * + * This method is called from the WebView thread. To do a non-trivial amount of work, use: + * cordova.getThreadPool().execute(runnable); + * + * To run on the UI thread, use: + * cordova.getActivity().runOnUiThread(runnable); + * + * @param action The action to execute. + * @param args The exec() arguments. + * @param callbackId The callback id used when calling back into JavaScript. + * @return Whether the action was valid. + */ + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + return false; + } + + /** + * Called when the system is about to start resuming a previous activity. + * + * @param multitasking Flag indicating if multitasking is turned on for app + */ + public void onPause(boolean multitasking) { + } + + /** + * Called when the activity will start interacting with the user. + * + * @param multitasking Flag indicating if multitasking is turned on for app + */ + public void onResume(boolean multitasking) { + } + + /** + * Called when the activity receives a new intent. + */ + public void onNewIntent(Intent intent) { + } + + /** + * The final call you receive before your activity is destroyed. + */ + public void onDestroy() { + } + + /** + * Called when a message is sent to plugin. + * + * @param id The message id + * @param data The message data + * @return Object to stop propagation or null + */ + public Object onMessage(String id, Object data) { + return null; + } + + /** + * 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 data An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). + */ + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + } + + /** + * By specifying a in plugins.xml you can map a URL (using startsWith atm) to this method. + * + * @param url The URL that is trying to be loaded in the Cordova webview. + * @return Return true to prevent the URL from loading. Default is false. + */ + public boolean onOverrideUrlLoading(String url) { + return false; + } + + /** + * Called when the WebView does a top-level navigation or refreshes. + * + * Plugins should stop any long-running processes and clean up internal state. + * + * Does nothing by default. + */ + public void onReset() { + } +} diff --git a/framework/src/org/apache/cordova/api/LegacyContext.java b/framework/src/org/apache/cordova/api/LegacyContext.java index 8942cd36..b8bc0ae8 100644 --- a/framework/src/org/apache/cordova/api/LegacyContext.java +++ b/framework/src/org/apache/cordova/api/LegacyContext.java @@ -65,13 +65,13 @@ public class LegacyContext implements CordovaInterface { } @Deprecated - public void setActivityResultCallback(Plugin arg0) { + public void setActivityResultCallback(CordovaPlugin arg0) { Log.i(LOG_TAG, "Replace ctx.setActivityResultCallback() with cordova.setActivityResultCallback()"); this.cordova.setActivityResultCallback(arg0); } @Deprecated - public void startActivityForResult(Plugin arg0, Intent arg1, int arg2) { + public void startActivityForResult(CordovaPlugin arg0, Intent arg1, int arg2) { Log.i(LOG_TAG, "Replace ctx.startActivityForResult() with cordova.startActivityForResult()"); this.cordova.startActivityForResult(arg0, arg1, arg2); } diff --git a/framework/src/org/apache/cordova/api/Plugin.java b/framework/src/org/apache/cordova/api/Plugin.java index e856b881..72171f2a 100755 --- a/framework/src/org/apache/cordova/api/Plugin.java +++ b/framework/src/org/apache/cordova/api/Plugin.java @@ -20,42 +20,29 @@ package org.apache.cordova.api; import org.apache.cordova.CordovaWebView; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; -import android.content.Intent; - -import android.util.Log; /** - * Plugin interface must be implemented by any plugin classes. - * - * The execute method is called by the PluginManager. + * Legacy Plugin class. This acts as a shim to support the old execute() signature. + * New plugins should extend CordovaPlugin directly. */ -public abstract class Plugin { - - public String id; - public CordovaWebView webView; // WebView object +@Deprecated +public abstract class Plugin extends CordovaPlugin { public LegacyContext ctx; // LegacyContext object - public CordovaInterface cordova; - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. - * @param callbackId The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. - */ public abstract PluginResult execute(String action, JSONArray args, String callbackId); - /** - * Identifies if action to be executed returns a value and should be run synchronously. - * - * @param action The action to execute - * @return T=returns value - */ public boolean isSynch(String action) { return false; } + + @Override + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); + this.setContext(cordova); + this.setView(webView); + } /** * Sets the context of the Plugin. This can then be used to do things like @@ -77,66 +64,35 @@ public abstract class Plugin { public void setView(CordovaWebView webView) { this.webView = webView; } - - /** - * Called when the system is about to start resuming a previous activity. - * - * @param multitasking Flag indicating if multitasking is turned on for app - */ - public void onPause(boolean multitasking) { - } - - /** - * Called when the activity will start interacting with the user. - * - * @param multitasking Flag indicating if multitasking is turned on for app - */ - public void onResume(boolean multitasking) { - } - - /** - * Called when the activity receives a new intent. - */ - public void onNewIntent(Intent intent) { - } - - /** - * The final call you receive before your activity is destroyed. - */ - public void onDestroy() { - } - - /** - * Called when a message is sent to plugin. - * - * @param id The message id - * @param data The message data - * @return Object to stop propagation or null - */ - public Object onMessage(String id, Object data) { - return null; - } - - /** - * 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 data An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). - */ - public void onActivityResult(int requestCode, int resultCode, Intent intent) { - } - - /** - * By specifying a in plugins.xml you can map a URL (using startsWith atm) to this method. - * - * @param url The URL that is trying to be loaded in the Cordova webview. - * @return Return true to prevent the URL from loading. Default is false. - */ - public boolean onOverrideUrlLoading(String url) { - return false; + + @Override + public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + final String callbackId = callbackContext.getCallbackId(); + boolean runAsync = !isSynch(action); + if (runAsync) { + // Run this on a different thread so that this one can return back to JS + cordova.getThreadPool().execute(new Runnable() { + public void run() { + PluginResult cr; + try { + cr = execute(action, args, callbackId); + } catch (Throwable e) { + cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); + } + sendPluginResult(cr, callbackId); + } + }); + } else { + PluginResult cr = execute(action, args, callbackId); + + // Interpret a null response as NO_RESULT, which *does* clear the callbacks on the JS side. + if (cr == null) { + cr = new PluginResult(PluginResult.Status.NO_RESULT); + } + + callbackContext.sendPluginResult(cr); + } + return true; } /** @@ -161,8 +117,8 @@ public abstract class Plugin { * that execute should return null and the callback from the async operation can * call success(...) or error(...) * - * @param pluginResult The result to return. - * @param callbackId The callback id used when calling back into JavaScript. + * @param pluginResult The result to return. + * @param callbackId The callback id used when calling back into JavaScript. */ public void success(PluginResult pluginResult, String callbackId) { this.webView.sendPluginResult(pluginResult, callbackId); @@ -171,8 +127,8 @@ public abstract class Plugin { /** * Helper for success callbacks that just returns the Status.OK by default * - * @param message The message to add to the success result. - * @param callbackId The callback id used when calling back into JavaScript. + * @param message The message to add to the success result. + * @param callbackId The callback id used when calling back into JavaScript. */ public void success(JSONObject message, String callbackId) { this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId); @@ -181,8 +137,8 @@ public abstract class Plugin { /** * Helper for success callbacks that just returns the Status.OK by default * - * @param message The message to add to the success result. - * @param callbackId The callback id used when calling back into JavaScript. + * @param message The message to add to the success result. + * @param callbackId The callback id used when calling back into JavaScript. */ public void success(String message, String callbackId) { this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId); @@ -191,8 +147,8 @@ public abstract class Plugin { /** * Call the JavaScript error callback for this plugin. * - * @param pluginResult The result to return. - * @param callbackId The callback id used when calling back into JavaScript. + * @param pluginResult The result to return. + * @param callbackId The callback id used when calling back into JavaScript. */ public void error(PluginResult pluginResult, String callbackId) { this.webView.sendPluginResult(pluginResult, callbackId); @@ -201,8 +157,8 @@ public abstract class Plugin { /** * Helper for error callbacks that just returns the Status.ERROR by default * - * @param message The message to add to the error result. - * @param callbackId The callback id used when calling back into JavaScript. + * @param message The message to add to the error result. + * @param callbackId The callback id used when calling back into JavaScript. */ public void error(JSONObject message, String callbackId) { this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId); @@ -211,20 +167,11 @@ public abstract class Plugin { /** * Helper for error callbacks that just returns the Status.ERROR by default * - * @param message The message to add to the error result. - * @param callbackId The callback id used when calling back into JavaScript. + * @param message The message to add to the error result. + * @param callbackId The callback id used when calling back into JavaScript. */ public void error(String message, String callbackId) { this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId); } - /** - * Called when the WebView does a top-level navigation or refreshes. - * - * Plugins should stop any long-running processes and clean up internal state. - * - * Does nothing by default. - */ - public void onReset() { - } } diff --git a/framework/src/org/apache/cordova/api/PluginEntry.java b/framework/src/org/apache/cordova/api/PluginEntry.java index e32e0983..9b9af6bc 100755 --- a/framework/src/org/apache/cordova/api/PluginEntry.java +++ b/framework/src/org/apache/cordova/api/PluginEntry.java @@ -43,7 +43,7 @@ public class PluginEntry { * Plugin objects are only created when they are called from JavaScript. (see PluginManager.exec) * The exception is if the onload flag is set, then they are created when PluginManager is initialized. */ - public Plugin plugin = null; + public CordovaPlugin plugin = null; /** * Flag that indicates the plugin object should be created when PluginManager is initialized. @@ -69,7 +69,7 @@ public class PluginEntry { * * @return The plugin object */ - public Plugin createPlugin(CordovaWebView webView, CordovaInterface ctx) { + public CordovaPlugin createPlugin(CordovaWebView webView, CordovaInterface ctx) { if (this.plugin != null) { return this.plugin; } @@ -77,9 +77,8 @@ public class PluginEntry { @SuppressWarnings("rawtypes") Class c = getClassByName(this.pluginClass); if (isCordovaPlugin(c)) { - this.plugin = (Plugin) c.newInstance(); - this.plugin.setContext(ctx); - this.plugin.setView(webView); + this.plugin = (CordovaPlugin) c.newInstance(); + this.plugin.initialize(ctx, webView); return plugin; } } catch (Exception e) { @@ -106,16 +105,12 @@ public class PluginEntry { } /** - * Get the interfaces that a class implements and see if it implements the - * org.apache.cordova.api.Plugin interface. - * - * @param c The class to check the interfaces of. - * @return Boolean indicating if the class implements org.apache.cordova.api.Plugin + * Returns whether the given class extends CordovaPlugin. */ @SuppressWarnings("rawtypes") private boolean isCordovaPlugin(Class c) { if (c != null) { - return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.Plugin.class.isAssignableFrom(c); + return org.apache.cordova.api.CordovaPlugin.class.isAssignableFrom(c); } return false; } diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java index 9c2fa1ae..cafa79d3 100755 --- a/framework/src/org/apache/cordova/api/PluginManager.java +++ b/framework/src/org/apache/cordova/api/PluginManager.java @@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.Intent; import android.content.res.XmlResourceParser; +import android.util.Log; /** * PluginManager is exposed to JavaScript in the Cordova WebView. @@ -207,59 +208,31 @@ public class PluginManager { * how to deal with it. * @param callbackId String containing the id of the callback that is execute in JavaScript if * this is an async plugin call. - * @param args An Array literal string containing any arguments needed in the + * @param rawArgs An Array literal string containing any arguments needed in the * plugin execute method. * @return Whether the task completed synchronously. */ - public boolean exec(final String service, final String action, final String callbackId, final String jsonArgs) { - PluginResult cr = null; - final Plugin plugin = this.getPlugin(service); - boolean runAsync = !plugin.isSynch(action); - try { - final JSONArray args = new JSONArray(jsonArgs); - //final CordovaInterface ctx = this.ctx; - if (plugin != null) { - if (runAsync) { - // Run this on a different thread so that this one can return back to JS - ctx.getThreadPool().execute(new Runnable() { - public void run() { - try { - // Call execute on the plugin so that it can do it's thing - PluginResult cr = plugin.execute(action, args, callbackId); - app.sendPluginResult(cr, callbackId); - } catch (Exception e) { - PluginResult cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); - app.sendPluginResult(cr, callbackId); - } - } - }); - return false; - } else { - // Call execute on the plugin so that it can do it's thing - cr = plugin.execute(action, args, callbackId); - - // If no result to be sent and keeping callback, then no need to sent back to JavaScript - if ((cr.getStatus() == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) { - return true; - } - } - } - } catch (JSONException e) { - System.out.println("ERROR: " + e.toString()); - cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); - } - // if async we have already returned at this point unless there was an error... - if (runAsync) { - if (cr == null) { - cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION); - } + public boolean exec(String service, String action, String callbackId, String rawArgs) { + CordovaPlugin plugin = this.getPlugin(service); + if (plugin == null) { + PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION); app.sendPluginResult(cr, callbackId); + return true; } - if (cr == null) { - cr = new PluginResult(PluginResult.Status.NO_RESULT); + try { + CallbackContext callbackContext = new CallbackContext(callbackId, app); + boolean wasValidAction = plugin.execute(action, rawArgs, callbackContext); + if (!wasValidAction) { + PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION); + app.sendPluginResult(cr, callbackId); + return true; + } + return callbackContext.isFinished(); + } catch (JSONException e) { + PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); + app.sendPluginResult(cr, callbackId); + return true; } - app.sendPluginResult(cr, callbackId); - return true; } @Deprecated @@ -273,14 +246,14 @@ public class PluginManager { * If the service doesn't exist, then return null. * * @param service The name of the service. - * @return Plugin or null + * @return CordovaPlugin or null */ - private Plugin getPlugin(String service) { + private CordovaPlugin getPlugin(String service) { PluginEntry entry = this.entries.get(service); if (entry == null) { return null; } - Plugin plugin = entry.plugin; + CordovaPlugin plugin = entry.plugin; if (plugin == null) { plugin = entry.createPlugin(this.app, this.ctx); } @@ -403,7 +376,7 @@ public class PluginManager { public void onReset() { Iterator it = this.entries.values().iterator(); while (it.hasNext()) { - Plugin plugin = it.next().plugin; + CordovaPlugin plugin = it.next().plugin; if (plugin != null) { plugin.onReset(); }