diff options
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/javaaddons/JavaAddonManager.java')
-rw-r--r-- | mobile/android/base/java/org/mozilla/gecko/javaaddons/JavaAddonManager.java | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/javaaddons/JavaAddonManager.java b/mobile/android/base/java/org/mozilla/gecko/javaaddons/JavaAddonManager.java deleted file mode 100644 index 33a97955f..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/javaaddons/JavaAddonManager.java +++ /dev/null @@ -1,195 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.gecko.javaaddons; - -import android.content.Context; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.util.Log; -import dalvik.system.DexClassLoader; -import org.json.JSONException; -import org.json.JSONObject; -import org.mozilla.gecko.EventDispatcher; -import org.mozilla.gecko.util.GeckoEventListener; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * The manager for addon-provided Java code. - * - * Java code in addons can be loaded using the Dex:Load message, and unloaded - * via the Dex:Unload message. Addon classes loaded are checked for a constructor - * that takes a Map<String, Handler.Callback>. If such a constructor - * exists, it is called and the objects populated into the map by the constructor - * are registered as event listeners. If no such constructor exists, the default - * constructor is invoked instead. - * - * Note: The Map and Handler.Callback classes were used in this API definition - * rather than defining a custom class. This was done explicitly so that the - * addon code can be compiled against the android.jar provided in the Android - * SDK, rather than having to be compiled against Fennec source code. - * - * The Handler.Callback instances provided (as described above) are invoked with - * Message objects when the corresponding events are dispatched. The Bundle - * object attached to the Message will contain the "primitive" values from the - * JSON of the event. ("primitive" includes bool/int/long/double/String). If - * the addon callback wishes to synchronously return a value back to the event - * dispatcher, they can do so by inserting the response string into the bundle - * under the key "response". - */ -public class JavaAddonManager implements GeckoEventListener { - private static final String LOGTAG = "GeckoJavaAddonManager"; - - private static JavaAddonManager sInstance; - - private final EventDispatcher mDispatcher; - private final Map<String, Map<String, GeckoEventListener>> mAddonCallbacks; - - private Context mApplicationContext; - - public static JavaAddonManager getInstance() { - if (sInstance == null) { - sInstance = new JavaAddonManager(); - } - return sInstance; - } - - private JavaAddonManager() { - mDispatcher = EventDispatcher.getInstance(); - mAddonCallbacks = new HashMap<String, Map<String, GeckoEventListener>>(); - } - - public void init(Context applicationContext) { - if (mApplicationContext != null) { - // we've already done this registration. don't do it again - return; - } - mApplicationContext = applicationContext; - mDispatcher.registerGeckoThreadListener(this, - "Dex:Load", - "Dex:Unload"); - JavaAddonManagerV1.getInstance().init(applicationContext); - } - - @Override - public void handleMessage(String event, JSONObject message) { - try { - if (event.equals("Dex:Load")) { - String zipFile = message.getString("zipfile"); - String implClass = message.getString("impl"); - Log.d(LOGTAG, "Attempting to load classes.dex file from " + zipFile + " and instantiate " + implClass); - try { - File tmpDir = mApplicationContext.getDir("dex", 0); - DexClassLoader loader = new DexClassLoader(zipFile, tmpDir.getAbsolutePath(), null, mApplicationContext.getClassLoader()); - Class<?> c = loader.loadClass(implClass); - try { - Constructor<?> constructor = c.getDeclaredConstructor(Map.class); - Map<String, Handler.Callback> callbacks = new HashMap<String, Handler.Callback>(); - constructor.newInstance(callbacks); - registerCallbacks(zipFile, callbacks); - } catch (NoSuchMethodException nsme) { - Log.d(LOGTAG, "Did not find constructor with parameters Map<String, Handler.Callback>. Falling back to default constructor..."); - // fallback for instances with no constructor that takes a Map<String, Handler.Callback> - c.newInstance(); - } - } catch (Exception e) { - Log.e(LOGTAG, "Unable to load dex successfully", e); - } - } else if (event.equals("Dex:Unload")) { - String zipFile = message.getString("zipfile"); - unregisterCallbacks(zipFile); - } - } catch (JSONException e) { - Log.e(LOGTAG, "Exception handling message [" + event + "]:", e); - } - } - - private void registerCallbacks(String zipFile, Map<String, Handler.Callback> callbacks) { - Map<String, GeckoEventListener> addonCallbacks = mAddonCallbacks.get(zipFile); - if (addonCallbacks != null) { - Log.w(LOGTAG, "Found pre-existing callbacks for zipfile [" + zipFile + "]; aborting re-registration!"); - return; - } - addonCallbacks = new HashMap<String, GeckoEventListener>(); - for (String event : callbacks.keySet()) { - CallbackWrapper wrapper = new CallbackWrapper(callbacks.get(event)); - mDispatcher.registerGeckoThreadListener(wrapper, event); - addonCallbacks.put(event, wrapper); - } - mAddonCallbacks.put(zipFile, addonCallbacks); - } - - private void unregisterCallbacks(String zipFile) { - Map<String, GeckoEventListener> callbacks = mAddonCallbacks.remove(zipFile); - if (callbacks == null) { - Log.w(LOGTAG, "Attempting to unregister callbacks from zipfile [" + zipFile + "] which has no callbacks registered."); - return; - } - for (String event : callbacks.keySet()) { - mDispatcher.unregisterGeckoThreadListener(callbacks.get(event), event); - } - } - - private static class CallbackWrapper implements GeckoEventListener { - private final Handler.Callback mDelegate; - private Bundle mBundle; - - CallbackWrapper(Handler.Callback delegate) { - mDelegate = delegate; - } - - private Bundle jsonToBundle(JSONObject json) { - // XXX right now we only support primitive types; - // we don't recurse down into JSONArray or JSONObject instances - Bundle b = new Bundle(); - for (Iterator<?> keys = json.keys(); keys.hasNext(); ) { - try { - String key = (String)keys.next(); - Object value = json.get(key); - if (value instanceof Integer) { - b.putInt(key, (Integer)value); - } else if (value instanceof String) { - b.putString(key, (String)value); - } else if (value instanceof Boolean) { - b.putBoolean(key, (Boolean)value); - } else if (value instanceof Long) { - b.putLong(key, (Long)value); - } else if (value instanceof Double) { - b.putDouble(key, (Double)value); - } - } catch (JSONException e) { - Log.d(LOGTAG, "Error during JSON->bundle conversion", e); - } - } - return b; - } - - @Override - public void handleMessage(String event, JSONObject json) { - try { - if (mBundle != null) { - Log.w(LOGTAG, "Event [" + event + "] handler is re-entrant; response messages may be lost"); - } - mBundle = jsonToBundle(json); - Message msg = new Message(); - msg.setData(mBundle); - mDelegate.handleMessage(msg); - - JSONObject obj = new JSONObject(); - obj.put("response", mBundle.getString("response")); - EventDispatcher.sendResponse(json, obj); - mBundle = null; - } catch (Exception e) { - Log.e(LOGTAG, "Caught exception thrown from wrapped addon message handler", e); - } - } - } -} |