diff options
| author | 2009-11-24 14:58:09 -0500 | |
|---|---|---|
| committer | 2009-11-30 08:42:43 -0500 | |
| commit | cb37e71509da43e0d8d809591b09e8f5a582b5cd (patch) | |
| tree | 9ab9364ecdb573994d707b351c1b4d0f9ed5331a | |
| parent | e11a1b4d1a57dd6f42171aca3a4edb71438cbad1 (diff) | |
Refactoring plugins to use new java interfaces.
This change adds 3 new interfaces for plugins to the framework. This
change also includes extensive cleanup as we consolidate internal plugin
functions into the pluginManager. Also using the new interfaces we no
longer need to pass additional parameters in quite a few methods.
| -rw-r--r-- | core/java/android/webkit/PluginActivity.java | 40 | ||||
| -rw-r--r-- | core/java/android/webkit/PluginManager.java | 129 | ||||
| -rw-r--r-- | core/java/android/webkit/PluginUtil.java | 61 | ||||
| -rw-r--r-- | core/java/android/webkit/WebViewCore.java | 55 | ||||
| -rw-r--r-- | core/java/android/webkit/plugin/NativePlugin.java | 37 | ||||
| -rw-r--r-- | core/java/android/webkit/plugin/SurfaceDrawingModel.java | 37 | ||||
| -rw-r--r-- | core/java/android/webkit/plugin/WebkitPlugin.java | 36 |
7 files changed, 287 insertions, 108 deletions
diff --git a/core/java/android/webkit/PluginActivity.java b/core/java/android/webkit/PluginActivity.java index cda7b59dfc06..22d6ccb7eba2 100644 --- a/core/java/android/webkit/PluginActivity.java +++ b/core/java/android/webkit/PluginActivity.java @@ -19,6 +19,8 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; +import android.webkit.plugin.SurfaceDrawingModel; +import android.webkit.plugin.WebkitPlugin; /** * This activity is invoked when a plugin elects to go into full screen mode. @@ -28,8 +30,6 @@ public class PluginActivity extends Activity { /* package */ static final String INTENT_EXTRA_PACKAGE_NAME = "android.webkit.plugin.PACKAGE_NAME"; - /* package */ static final String INTENT_EXTRA_CLASS_NAME = - "android.webkit.plugin.CLASS_NAME"; /* package */ static final String INTENT_EXTRA_NPP_INSTANCE = "android.webkit.plugin.NPP_INSTANCE"; @@ -42,25 +42,31 @@ public class PluginActivity extends Activity { if (intent == null) { // No intent means no class to lookup. finish(); + return; } - final String packageName = - intent.getStringExtra(INTENT_EXTRA_PACKAGE_NAME); - final String className = intent.getStringExtra(INTENT_EXTRA_CLASS_NAME); + final String pkgName = intent.getStringExtra(INTENT_EXTRA_PACKAGE_NAME); final int npp = intent.getIntExtra(INTENT_EXTRA_NPP_INSTANCE, -1); - // Retrieve the PluginStub implemented in packageName.className - PluginStub stub = - PluginUtil.getPluginStub(this, packageName, className); - if (stub != null) { - View pluginView = stub.getFullScreenView(npp, this); - if (pluginView != null) { - setContentView(pluginView); - } else { - // No custom full-sreen view returned by the plugin, odd but - // just in case, finish the activity. - finish(); - } + // XXX retrieve the existing object instead of creating a new one + WebkitPlugin plugin = PluginManager.getInstance(null).getPluginInstance(pkgName, npp); + + if (plugin == null) { + //TODO log error + finish(); + return; + } + SurfaceDrawingModel fullScreenSurface = plugin.getFullScreenSurface(); + if(fullScreenSurface == null) { + //TODO log error + finish(); + return; + } + View pluginView = fullScreenSurface.getSurface(); + if (pluginView != null) { + setContentView(pluginView); } else { + // No custom full-sreen view returned by the plugin, odd but + // just in case, finish the activity. finish(); } } diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java index 4588f46e5771..88429c50442f 100644 --- a/core/java/android/webkit/PluginManager.java +++ b/core/java/android/webkit/PluginManager.java @@ -31,6 +31,8 @@ import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.os.SystemProperties; import android.util.Log; +import android.webkit.plugin.NativePlugin; +import android.webkit.plugin.WebkitPlugin; /** * Class for managing the relationship between the {@link WebView} and installed @@ -41,6 +43,12 @@ import android.util.Log; */ public class PluginManager { + private class PluginInfo { + public PackageInfo packageInfo; + public boolean isNative; + public Class<? extends WebkitPlugin> pluginClass; + } + /** * Service Action: A plugin wishes to be loaded in the WebView must provide * {@link android.content.IntentFilter IntentFilter} that accepts this @@ -60,11 +68,14 @@ public class PluginManager { private static final String LOGTAG = "webkit"; + private static final String PLUGIN_TYPE = "type"; + private static final String TYPE_NATIVE = "native"; + private static PluginManager mInstance = null; private final Context mContext; - private ArrayList<PackageInfo> mPackageInfoCache; + private ArrayList<PluginInfo> mPluginInfoCache; // Only plugin matches one of the signatures in the list can be loaded // inside the WebView process @@ -76,7 +87,7 @@ public class PluginManager { private PluginManager(Context context) { mContext = context; - mPackageInfoCache = new ArrayList<PackageInfo>(); + mPluginInfoCache = new ArrayList<PluginInfo>(); } public static synchronized PluginManager getInstance(Context context) { @@ -108,35 +119,44 @@ public class PluginManager { ArrayList<String> directories = new ArrayList<String>(); PackageManager pm = mContext.getPackageManager(); List<ResolveInfo> plugins = pm.queryIntentServices(new Intent( - PLUGIN_ACTION), PackageManager.GET_SERVICES); + PLUGIN_ACTION), PackageManager.GET_SERVICES + | PackageManager.GET_META_DATA); - synchronized(mPackageInfoCache) { + synchronized(mPluginInfoCache) { // clear the list of existing packageInfo objects - mPackageInfoCache.clear(); + mPluginInfoCache.clear(); for (ResolveInfo info : plugins) { + + // retrieve the plugin's service information ServiceInfo serviceInfo = info.serviceInfo; if (serviceInfo == null) { Log.w(LOGTAG, "Ignore bad plugin"); continue; } + + // retrieve information from the plugin's manifest PackageInfo pkgInfo; try { pkgInfo = pm.getPackageInfo(serviceInfo.packageName, PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES); } catch (NameNotFoundException e) { - Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName); + Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName); continue; } if (pkgInfo == null) { continue; } + + // check if their is a conflict in the lib directory names String directory = pkgInfo.applicationInfo.dataDir + "/lib"; if (directories.contains(directory)) { continue; } + + // check if the plugin has the required permissions String permissions[] = pkgInfo.requestedPermissions; if (permissions == null) { continue; @@ -151,6 +171,8 @@ public class PluginManager { if (!permissionOk) { continue; } + + // check to ensure the plugin is properly signed Signature signatures[] = pkgInfo.signatures; if (signatures == null) { continue; @@ -169,7 +191,51 @@ public class PluginManager { continue; } } - mPackageInfoCache.add(pkgInfo); + + PluginInfo pluginInfo = new PluginInfo(); + pluginInfo.packageInfo = pkgInfo; + + // determine the type of plugin from the manifest + if (serviceInfo.metaData == null) { + Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined"); + continue; + } + + String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE); + if (TYPE_NATIVE.equals(pluginType)) { + pluginInfo.isNative = true; + } else { + Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType); + continue; + } + + try { + Class<?> cls = getPluginClass(serviceInfo.packageName, serviceInfo.name); + + boolean classFound = false; + for(Class<?> implemented : cls.getInterfaces()) { + if (pluginInfo.isNative && implemented.equals(NativePlugin.class)) { + pluginInfo.pluginClass = cls.asSubclass(WebkitPlugin.class); + classFound = true; + break; + } + } + + if (!classFound) { + Log.e(LOGTAG, "The plugin's class'" + serviceInfo.name + "' does not extend the appropriate interface."); + continue; + } + + } catch (NameNotFoundException e) { + Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName); + continue; + } catch (ClassNotFoundException e) { + Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name); + continue; + } + + // if all checks have passed then make the plugin available + mPluginInfoCache.add(pluginInfo); directories.add(directory); } } @@ -177,6 +243,7 @@ public class PluginManager { return directories.toArray(new String[directories.size()]); } + /* package */ String getPluginsAPKName(String pluginLib) { // basic error checking on input params @@ -185,8 +252,9 @@ public class PluginManager { } // must be synchronized to ensure the consistency of the cache - synchronized(mPackageInfoCache) { - for (PackageInfo pkgInfo : mPackageInfoCache) { + synchronized(mPluginInfoCache) { + for (PluginInfo pluginInfo : mPluginInfoCache) { + PackageInfo pkgInfo = pluginInfo.packageInfo; if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) { return pkgInfo.packageName; } @@ -200,4 +268,47 @@ public class PluginManager { String getPluginSharedDataDirectory() { return mContext.getDir("plugins", 0).getPath(); } + + /* package */ + WebkitPlugin getPluginInstance(String pkgName, int npp) { + + // must be synchronized to ensure the consistency of the cache + synchronized(mPluginInfoCache) { + + // lookup plugin based on pkgName and instantiate if possible. + for (PluginInfo pluginInfo : mPluginInfoCache) { + + if (pluginInfo.packageInfo.packageName.equals(pkgName)) { + + try { + WebkitPlugin webkitPlugin = pluginInfo.pluginClass.newInstance(); + + if (pluginInfo.isNative) { + NativePlugin nativePlugin = (NativePlugin) webkitPlugin; + nativePlugin.initializePlugin(npp, mContext); + } + + return webkitPlugin; + } catch (Exception e) { + // Any number of things could have happened. Log the exception and + // return null. Careful not to use Log.e(LOGTAG, "String", e) + // because that reports the exception to the checkin service. + Log.e(LOGTAG, Log.getStackTraceString(e)); + } + break; + } + } + } + return null; + } + + /* package */ + Class<?> getPluginClass(String packageName, String className) + throws NameNotFoundException, ClassNotFoundException { + Context pluginContext = mContext.createPackageContext(packageName, + Context.CONTEXT_INCLUDE_CODE | + Context.CONTEXT_IGNORE_SECURITY); + ClassLoader pluginCL = pluginContext.getClassLoader(); + return pluginCL.loadClass(className); + } } diff --git a/core/java/android/webkit/PluginUtil.java b/core/java/android/webkit/PluginUtil.java deleted file mode 100644 index 33ccf9d205fc..000000000000 --- a/core/java/android/webkit/PluginUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed 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 android.webkit; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Log; - -class PluginUtil { - - private static final String LOGTAG = "PluginUtil"; - - /** - * - * @param packageName the name of the apk where the class can be found - * @param className the fully qualified name of a subclass of PluginStub - */ - /* package */ - static PluginStub getPluginStub(Context context, String packageName, - String className) { - try { - Class<?> stubClass = getPluginClass(context, packageName, className); - Object stubObject = stubClass.newInstance(); - - if (stubObject instanceof PluginStub) { - return (PluginStub) stubObject; - } else { - Log.e(LOGTAG, "The plugin class is not of type PluginStub"); - } - } catch (Exception e) { - // Any number of things could have happened. Log the exception and - // return null. Careful not to use Log.e(LOGTAG, "String", e) - // because that reports the exception to the checkin service. - Log.e(LOGTAG, Log.getStackTraceString(e)); - } - return null; - } - - /* package */ - static Class<?> getPluginClass(Context context, String packageName, - String className) throws NameNotFoundException, ClassNotFoundException { - Context pluginContext = context.createPackageContext(packageName, - Context.CONTEXT_INCLUDE_CODE | - Context.CONTEXT_IGNORE_SECURITY); - ClassLoader pluginCL = pluginContext.getClassLoader(); - return pluginCL.loadClass(className); - } -} diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 769f0b1a6d3f..be36fe0fb97c 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -41,6 +41,8 @@ import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; +import android.webkit.plugin.SurfaceDrawingModel; +import android.webkit.plugin.WebkitPlugin; import java.util.ArrayList; import java.util.Collection; @@ -2175,15 +2177,16 @@ final class WebViewCore { return null; } - String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName); + PluginManager pluginManager = PluginManager.getInstance(null); + + String pkgName = pluginManager.getPluginsAPKName(libName); if (pkgName == null) { Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); return null; } - Class<?> pluginClass = null; try { - pluginClass = PluginUtil.getPluginClass(mWebView.getContext(), pkgName, clsName); + return pluginManager.getPluginClass(pkgName, clsName); } catch (NameNotFoundException e) { Log.e(LOGTAG, "Unable to find plugin classloader for the apk (" + pkgName + ")"); } catch (ClassNotFoundException e) { @@ -2191,12 +2194,29 @@ final class WebViewCore { ") in the apk (" + pkgName + ")"); } - return pluginClass; + return null; + } + + private WebkitPlugin createPluginJavaInstance(String libName, int npp) { + + if (mWebView == null) { + return null; + } + + PluginManager pluginManager = PluginManager.getInstance(null); + + String pkgName = pluginManager.getPluginsAPKName(libName); + if (pkgName == null) { + Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); + return null; + } + + return pluginManager.getPluginInstance(pkgName, npp); } - + // called by JNI. PluginWidget function to launch an activity and overlays // the activity with the View provided by the plugin class. - private void startFullScreenPluginActivity(String libName, String clsName, int npp) { + private void startFullScreenPluginActivity(String libName, int npp) { if (mWebView == null) { return; } @@ -2209,40 +2229,33 @@ final class WebViewCore { Intent intent = new Intent("android.intent.webkit.PLUGIN"); intent.putExtra(PluginActivity.INTENT_EXTRA_PACKAGE_NAME, pkgName); - intent.putExtra(PluginActivity.INTENT_EXTRA_CLASS_NAME, clsName); intent.putExtra(PluginActivity.INTENT_EXTRA_NPP_INSTANCE, npp); mWebView.getContext().startActivity(intent); } // called by JNI. PluginWidget functions for creating an embedded View for // the surface drawing model. - private ViewManager.ChildView createSurface(String libName, String clsName, - int npp, int x, int y, int width, int height) { + private ViewManager.ChildView createSurface(WebkitPlugin webkitPlugin, + int x, int y, int width, int height) { + if (mWebView == null) { return null; } - String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName); - if (pkgName == null) { - Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); + SurfaceDrawingModel embeddedSurface = webkitPlugin.getEmbeddedSurface(); + if(embeddedSurface == null) { + Log.e(LOGTAG, "Attempted to create an embedded surface with a null drawing model"); return null; } - PluginStub stub =PluginUtil.getPluginStub(mWebView.getContext(),pkgName, clsName); - if (stub == null) { - Log.e(LOGTAG, "Unable to find plugin class (" + clsName + - ") in the apk (" + pkgName + ")"); - return null; - } - - View pluginView = stub.getEmbeddedView(npp, mWebView.getContext()); + View pluginView = embeddedSurface.getSurface(); ViewManager.ChildView view = mWebView.mViewManager.createView(); view.mView = pluginView; view.attachView(x, y, width, height); return view; } - + private void updateSurface(ViewManager.ChildView childView, int x, int y, int width, int height) { childView.attachView(x, y, width, height); diff --git a/core/java/android/webkit/plugin/NativePlugin.java b/core/java/android/webkit/plugin/NativePlugin.java new file mode 100644 index 000000000000..5019c35e74ef --- /dev/null +++ b/core/java/android/webkit/plugin/NativePlugin.java @@ -0,0 +1,37 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package android.webkit.plugin; + +import android.content.Context; + +/** + * + * @hide pending API solidification + */ +public interface NativePlugin extends WebkitPlugin { + + void initializePlugin(int npp, Context context); + +} diff --git a/core/java/android/webkit/plugin/SurfaceDrawingModel.java b/core/java/android/webkit/plugin/SurfaceDrawingModel.java new file mode 100644 index 000000000000..93ba46667f27 --- /dev/null +++ b/core/java/android/webkit/plugin/SurfaceDrawingModel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package android.webkit.plugin; + +import android.view.View; + +/** + * + * @hide pending API solidification + */ +public interface SurfaceDrawingModel { + + public View getSurface(); + +} diff --git a/core/java/android/webkit/plugin/WebkitPlugin.java b/core/java/android/webkit/plugin/WebkitPlugin.java new file mode 100644 index 000000000000..3d13c1cbe086 --- /dev/null +++ b/core/java/android/webkit/plugin/WebkitPlugin.java @@ -0,0 +1,36 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package android.webkit.plugin; + +/** + * + * @hide pending API solidification + */ +public interface WebkitPlugin { + + SurfaceDrawingModel getEmbeddedSurface(); + SurfaceDrawingModel getFullScreenSurface(); + +} |