diff options
| -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(); + +} |