mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-20 23:56:20 +08:00
[CB-352] Support initializing DroidGap with existing WebView, WebViewClient and webViewChrome.
[CB-353] Create PluginEntry object to use by PluginManager.
This commit is contained in:
parent
04b3e4d847
commit
7e70d76232
@ -64,7 +64,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
|
||||
// First give any plugins the chance to handle the url themselves
|
||||
if (this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
if ((this.ctx.pluginManager != null) && this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
}
|
||||
|
||||
// If dialing phone (tel:5551212)
|
||||
|
@ -56,6 +56,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebSettings.LayoutAlgorithm;
|
||||
import android.webkit.WebView;
|
||||
@ -345,22 +346,33 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and initialize web container.
|
||||
* Create and initialize web container with default web view objects.
|
||||
*/
|
||||
public void init() {
|
||||
this.init(new WebView(DroidGap.this), new CordovaWebViewClient(this), new CordovaChromeClient(DroidGap.this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize web container with web view objects.
|
||||
*
|
||||
* @param webView
|
||||
* @param webViewClient
|
||||
* @param webChromeClient
|
||||
*/
|
||||
public void init(WebView webView, WebViewClient webViewClient, WebChromeClient webChromeClient) {
|
||||
LOG.d(TAG, "DroidGap.init()");
|
||||
|
||||
// Create web container
|
||||
this.appView = new WebView(DroidGap.this);
|
||||
// Set up web container
|
||||
this.appView = webView;
|
||||
this.appView.setId(100);
|
||||
|
||||
|
||||
this.appView.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
1.0F));
|
||||
|
||||
this.appView.setWebChromeClient(new CordovaChromeClient(DroidGap.this));
|
||||
this.setWebViewClient(this.appView, new CordovaWebViewClient(this));
|
||||
this.appView.setWebChromeClient(webChromeClient);
|
||||
this.setWebViewClient(this.appView, webViewClient);
|
||||
|
||||
this.appView.setInitialScale(0);
|
||||
this.appView.setVerticalScrollBarEnabled(false);
|
||||
@ -393,6 +405,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
|
||||
// Clear cancel flag
|
||||
this.cancelLoadUrl = false;
|
||||
|
||||
// Create plugin manager
|
||||
this.pluginManager = new PluginManager(this.appView, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,12 +513,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
else {
|
||||
me.callbackServer.reinit(url);
|
||||
}
|
||||
if (me.pluginManager == null) {
|
||||
me.pluginManager = new PluginManager(me.appView, me);
|
||||
}
|
||||
else {
|
||||
me.pluginManager.reinit();
|
||||
}
|
||||
me.pluginManager.init();
|
||||
|
||||
// If loadingDialog property, then show the App loading dialog for first page of app
|
||||
String loading = null;
|
||||
@ -834,8 +844,10 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onPause.fire();}catch(e){console.log('exception firing pause event from native');};");
|
||||
|
||||
// Forward to plugins
|
||||
this.pluginManager.onPause(this.keepRunning);
|
||||
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onPause(this.keepRunning);
|
||||
}
|
||||
|
||||
// If app doesn't want to run in background
|
||||
if (!this.keepRunning) {
|
||||
|
||||
@ -852,7 +864,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
//Forward to plugins
|
||||
this.pluginManager.onNewIntent(intent);
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -875,8 +889,10 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onResume.fire();}catch(e){console.log('exception firing resume event from native');};");
|
||||
|
||||
// Forward to plugins
|
||||
this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
|
||||
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
|
||||
}
|
||||
|
||||
// If app doesn't want to run in background
|
||||
if (!this.keepRunning || this.activityResultKeepRunning) {
|
||||
|
||||
@ -942,7 +958,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
*/
|
||||
@Deprecated
|
||||
public void addService(String serviceType, String className) {
|
||||
this.pluginManager.addService(serviceType, className);
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.addService(serviceType, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
119
framework/src/org/apache/cordova/api/PluginEntry.java
Executable file
119
framework/src/org/apache/cordova/api/PluginEntry.java
Executable file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
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 android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* This class represents a service entry object.
|
||||
*/
|
||||
public class PluginEntry {
|
||||
|
||||
/**
|
||||
* The name of the service that this plugin implements
|
||||
*/
|
||||
public String service = "";
|
||||
|
||||
/**
|
||||
* The plugin class name that implements the service.
|
||||
*/
|
||||
public String pluginClass = "";
|
||||
|
||||
/**
|
||||
* The plugin object.
|
||||
* 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 IPlugin plugin = null;
|
||||
|
||||
/**
|
||||
* Flag that indicates the plugin object should be created when PluginManager is initialized.
|
||||
*/
|
||||
public boolean onload = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param service The name of the service
|
||||
* @param pluginClass The plugin class name
|
||||
* @param onload Create plugin object when HTML page is loaded
|
||||
*/
|
||||
public PluginEntry(String service, String pluginClass, boolean onload) {
|
||||
this.service = service;
|
||||
this.pluginClass = pluginClass;
|
||||
this.onload = onload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plugin object.
|
||||
* If plugin is already created, then just return it.
|
||||
*
|
||||
* @return The plugin object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public IPlugin createPlugin(WebView webView, CordovaInterface ctx) {
|
||||
if (this.plugin != null) {
|
||||
return this.plugin;
|
||||
}
|
||||
try {
|
||||
Class c = getClassByName(this.pluginClass);
|
||||
if (isCordovaPlugin(c)) {
|
||||
this.plugin = (IPlugin) c.newInstance();
|
||||
this.plugin.setContext(ctx);
|
||||
this.plugin.setView(webView);
|
||||
return plugin;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error adding plugin " + this.pluginClass + ".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isCordovaPlugin(Class c) {
|
||||
if (c != null) {
|
||||
return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
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 java.io.IOException;
|
||||
@ -29,7 +29,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
@ -39,321 +38,324 @@ import android.webkit.WebView;
|
||||
* from JavaScript.
|
||||
*/
|
||||
public class PluginManager {
|
||||
private static String TAG = "PluginManager";
|
||||
|
||||
// List of service entries
|
||||
private final HashMap<String, PluginEntry> entries = new HashMap<String, PluginEntry>();
|
||||
|
||||
private final CordovaInterface ctx;
|
||||
private final WebView app;
|
||||
|
||||
// Flag to track first time through
|
||||
private boolean firstRun;
|
||||
|
||||
private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
|
||||
private HashMap<String, String> services = new HashMap<String,String>();
|
||||
|
||||
private final CordovaInterface ctx;
|
||||
private final WebView app;
|
||||
|
||||
// Map URL schemes like foo: to plugins that want to handle those schemes
|
||||
// This would allow how all URLs are handled to be offloaded to a plugin
|
||||
protected HashMap<String, String> urlMap = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param app
|
||||
* @param ctx
|
||||
*/
|
||||
public PluginManager(WebView app, CordovaInterface ctx) {
|
||||
this.ctx = ctx;
|
||||
this.app = app;
|
||||
this.loadPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-init when loading a new HTML page into webview.
|
||||
*/
|
||||
public void reinit() {
|
||||
|
||||
// Stop plugins on current HTML page and discard
|
||||
this.onPause(false);
|
||||
this.onDestroy();
|
||||
this.plugins = new HashMap<String, IPlugin>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugins from res/xml/plugins.xml
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
|
||||
if (id == 0) { pluginConfigurationMissing(); }
|
||||
XmlResourceParser xml = ctx.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
String pluginClass = "", pluginName = "";
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("plugin")) {
|
||||
pluginClass = xml.getAttributeValue(null, "value");
|
||||
pluginName = xml.getAttributeValue(null, "name");
|
||||
//System.out.println("Plugin: "+name+" => "+value);
|
||||
this.addService(pluginName, pluginClass);
|
||||
|
||||
// Create plugin at load time if attribute "onload"
|
||||
if ("true".equals(xml.getAttributeValue(null, "onload"))) {
|
||||
this.getPlugin(pluginName);
|
||||
}
|
||||
} else if (strNode.equals("url-filter")) {
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a request for execution and fulfills it by finding the appropriate
|
||||
* Java class and calling it's execute method.
|
||||
*
|
||||
* PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
|
||||
* string is returned that will indicate if any errors have occurred when trying to find
|
||||
* or execute the class denoted by the clazz argument.
|
||||
*
|
||||
* @param service String containing the service to run
|
||||
* @param action String containt the action that the class is supposed to perform. This is
|
||||
* passed to the plugin execute method and it is up to the plugin developer
|
||||
* 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
|
||||
* plugin execute method.
|
||||
* @param async Boolean indicating whether the calling JavaScript code is expecting an
|
||||
* immediate return value. If true, either Cordova.callbackSuccess(...) or
|
||||
* Cordova.callbackError(...) is called once the plugin code has executed.
|
||||
*
|
||||
* @return JSON encoded string with a response message and status.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) {
|
||||
PluginResult cr = null;
|
||||
boolean runAsync = async;
|
||||
try {
|
||||
final JSONArray args = new JSONArray(jsonArgs);
|
||||
final IPlugin plugin = this.getPlugin(service);
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
if (plugin != null) {
|
||||
runAsync = async && !plugin.isSynch(action);
|
||||
if (runAsync) {
|
||||
// Run this on a different thread so that this one can return back to JS
|
||||
Thread thread = new Thread(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);
|
||||
int status = cr.getStatus();
|
||||
|
||||
// If no result to be sent and keeping callback, then no need to sent back to JavaScript
|
||||
if ((status == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
|
||||
}
|
||||
|
||||
// Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
|
||||
else if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
|
||||
ctx.sendJavascript(cr.toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
// If error
|
||||
else {
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
PluginResult cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
return "";
|
||||
} 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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
return ( cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isCordovaPlugin(Class c) {
|
||||
if (c != null) {
|
||||
return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected HashMap<String, String> urlMap = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Add plugin to be loaded and cached. This creates an instance of the plugin.
|
||||
* If plugin is already created, then just return it.
|
||||
* Constructor.
|
||||
*
|
||||
* @param className The class to load
|
||||
* @param clazz The class object (must be a class object of the className)
|
||||
* @param callbackId The callback id to use when calling back into JavaScript
|
||||
* @return The plugin
|
||||
* @param app
|
||||
* @param ctx
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private IPlugin addPlugin(String pluginName, String className) {
|
||||
try {
|
||||
Class c = getClassByName(className);
|
||||
if (isCordovaPlugin(c)) {
|
||||
IPlugin plugin = (IPlugin)c.newInstance();
|
||||
this.plugins.put(className, plugin);
|
||||
plugin.setContext(this.ctx);
|
||||
plugin.setView(this.app);
|
||||
return plugin;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error adding plugin "+className+".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loaded plugin.
|
||||
*
|
||||
* If the plugin is not already loaded then load it.
|
||||
*
|
||||
* @param className The class of the loaded plugin.
|
||||
* @return
|
||||
*/
|
||||
private IPlugin getPlugin(String pluginName) {
|
||||
String className = this.services.get(pluginName);
|
||||
if (this.plugins.containsKey(className)) {
|
||||
return this.plugins.get(className);
|
||||
} else {
|
||||
return this.addPlugin(pluginName, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
* This does not create the class instance. It just maps service name to class name.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
public void addService(String serviceType, String className) {
|
||||
this.services.put(serviceType, className);
|
||||
public PluginManager(WebView app, CordovaInterface ctx) {
|
||||
this.ctx = ctx;
|
||||
this.app = app;
|
||||
this.firstRun = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
* Init when loading a new HTML page into webview.
|
||||
*/
|
||||
public void init() {
|
||||
LOG.d(TAG, "init()");
|
||||
|
||||
// If first time, then load plugins from plugins.xml file
|
||||
if (firstRun) {
|
||||
this.loadPlugins();
|
||||
firstRun = false;
|
||||
}
|
||||
|
||||
// Stop plugins on current HTML page and discard plugin objects
|
||||
else {
|
||||
this.onPause(false);
|
||||
this.onDestroy();
|
||||
this.clearPluginObjects();
|
||||
}
|
||||
|
||||
// Start up all plugins that have onload specified
|
||||
this.startupPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugins from res/xml/plugins.xml
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
|
||||
if (id == 0) {
|
||||
pluginConfigurationMissing();
|
||||
}
|
||||
XmlResourceParser xml = ctx.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
String service = "", pluginClass = "";
|
||||
boolean onload = false;
|
||||
PluginEntry entry = null;
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("plugin")) {
|
||||
service = xml.getAttributeValue(null, "name");
|
||||
pluginClass = xml.getAttributeValue(null, "value");
|
||||
// System.out.println("Plugin: "+name+" => "+value);
|
||||
onload = "true".equals(xml.getAttributeValue(null, "onload"));
|
||||
entry = new PluginEntry(service, pluginClass, onload);
|
||||
this.addService(entry);
|
||||
} else if (strNode.equals("url-filter")) {
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), service);
|
||||
}
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all plugin objects.
|
||||
*/
|
||||
public void clearPluginObjects() {
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
entry.plugin = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plugins objects that have onload set.
|
||||
*/
|
||||
public void startupPlugins() {
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.onload) {
|
||||
entry.createPlugin(this.app, this.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a request for execution and fulfills it by finding the appropriate
|
||||
* Java class and calling it's execute method.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
* PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
|
||||
* string is returned that will indicate if any errors have occurred when trying to find
|
||||
* or execute the class denoted by the clazz argument.
|
||||
*
|
||||
* @param service String containing the service to run
|
||||
* @param action String containt the action that the class is supposed to perform. This is
|
||||
* passed to the plugin execute method and it is up to the plugin developer
|
||||
* 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
|
||||
* plugin execute method.
|
||||
* @param async Boolean indicating whether the calling JavaScript code is expecting an
|
||||
* immediate return value. If true, either Cordova.callbackSuccess(...) or
|
||||
* Cordova.callbackError(...) is called once the plugin code has executed.
|
||||
*
|
||||
* @return JSON encoded string with a response message and status.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) {
|
||||
PluginResult cr = null;
|
||||
boolean runAsync = async;
|
||||
try {
|
||||
final JSONArray args = new JSONArray(jsonArgs);
|
||||
final IPlugin plugin = this.getPlugin(service);
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
if (plugin != null) {
|
||||
runAsync = async && !plugin.isSynch(action);
|
||||
if (runAsync) {
|
||||
// Run this on a different thread so that this one can return back to JS
|
||||
Thread thread = new Thread(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);
|
||||
int status = cr.getStatus();
|
||||
|
||||
// If no result to be sent and keeping callback, then no need to sent back to JavaScript
|
||||
if ((status == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
|
||||
}
|
||||
|
||||
// Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
|
||||
else if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
|
||||
ctx.sendJavascript(cr.toSuccessCallbackString(callbackId));
|
||||
}
|
||||
|
||||
// If error
|
||||
else {
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
PluginResult cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
return "";
|
||||
} 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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
return (cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin object that implements the service.
|
||||
* If the plugin object does not already exist, then create it.
|
||||
* If the service doesn't exist, then return null.
|
||||
*
|
||||
* @param service The name of the service.
|
||||
* @return IPlugin or null
|
||||
*/
|
||||
private IPlugin getPlugin(String service) {
|
||||
PluginEntry entry = entries.get(service);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
IPlugin plugin = entry.plugin;
|
||||
if (plugin == null) {
|
||||
plugin = entry.createPlugin(this.app, this.ctx);
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plugin class that implements a service to the service entry table.
|
||||
* This does not create the plugin object instance.
|
||||
*
|
||||
* @param service The service name
|
||||
* @param className The plugin class name
|
||||
*/
|
||||
public void addService(String service, String className) {
|
||||
PluginEntry entry = new PluginEntry(service, className, false);
|
||||
this.addService(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plugin class that implements a service to the service entry table.
|
||||
* This does not create the plugin object instance.
|
||||
*
|
||||
* @param entry The plugin entry
|
||||
*/
|
||||
public void addService(PluginEntry entry) {
|
||||
this.entries.put(entry.service, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onPause(multitasking);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onPause(multitasking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume(boolean multitasking) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onResume(multitasking);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onResume(multitasking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onDestroy();
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
* Send a message to all plugins.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void postMessage(String id, Object data) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onMessage(id, data);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onMessage(id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onNewIntent(intent);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the URL of the webview changes.
|
||||
*
|
||||
* @param url The URL that is being changed to.
|
||||
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
|
||||
* @param url The URL that is being changed to.
|
||||
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
|
||||
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
HashMap.Entry<String, String> pairs = it.next();
|
||||
if (url.startsWith(pairs.getKey())) {
|
||||
return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
|
||||
return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pluginConfigurationMissing() {
|
||||
System.err.println("=====================================================================================");
|
||||
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");
|
||||
System.err.println("https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=blob;f=framework/res/xml/plugins.xml");
|
||||
System.err.println("=====================================================================================");
|
||||
}
|
||||
private void pluginConfigurationMissing() {
|
||||
System.err.println("=====================================================================================");
|
||||
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");
|
||||
System.err.println("https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=blob;f=framework/res/xml/plugins.xml");
|
||||
System.err.println("=====================================================================================");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user