Merge change 1664

* changes:
  Added PluginManager to handle getting all the plugin directories from PackageManager.
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index ba3f78c..6229da7 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -109,6 +109,8 @@
             CacheManager.init(context);
             // create CookieSyncManager with current Context
             CookieSyncManager.createInstance(context);
+            // create PluginManager with current Context
+            PluginManager.getInstance(context);
         }
         AssetManager am = context.getAssets();
         nativeCreateFrame(w, am, proxy.getBackForwardList());
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 1831c92..bf05518 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -40,6 +40,9 @@
     private boolean mTimerPaused;
     private boolean mHasDeferredTimers;
 
+    /* package */
+    static final int REFRESH_PLUGINS = 100;
+
     /**
      * Construct a new JWebCoreJavaBridge to interface with
      * WebCore timers and cookies.
@@ -84,6 +87,11 @@
             case FUNCPTR_MESSAGE:
                 nativeServiceFuncPtrQueue();
                 break;
+            case REFRESH_PLUGINS:
+                nativeUpdatePluginDirectories(PluginManager.getInstance(null)
+                        .getPluginDirecoties(), ((Boolean) msg.obj)
+                        .booleanValue());
+                break;
         }
     }
     
@@ -171,6 +179,13 @@
     }
 
     /**
+     * Returns an array of plugin directoies
+     */
+    private String[] getPluginDirectories() {
+        return PluginManager.getInstance(null).getPluginDirecoties();
+    }
+
+    /**
      * setSharedTimer
      * @param timemillis The relative time when the timer should fire
      */
@@ -210,5 +225,7 @@
     private native void nativeConstructor();
     private native void nativeFinalize();
     private native void sharedTimerFired();
+    private native void nativeUpdatePluginDirectories(String[] directories,
+            boolean reload);
     public native void setNetworkOnLine(boolean online);
 }
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
new file mode 100644
index 0000000..e4a44b92
--- /dev/null
+++ b/core/java/android/webkit/PluginManager.java
@@ -0,0 +1,157 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+/**
+ * Class for managing the relationship between the {@link WebView} and installed
+ * plugins in the system. You can find this class through
+ * {@link PluginManager#getInstance}.
+ * 
+ * @hide pending API solidification
+ */
+public class PluginManager {
+
+    /**
+     * Service Action: A plugin wishes to be loaded in the WebView must provide
+     * {@link android.content.IntentFilter IntentFilter} that accepts this
+     * action in their AndroidManifest.xml.
+     * <p>
+     * TODO: we may change this to a new PLUGIN_ACTION if this is going to be
+     * public.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
+
+    /**
+     * A plugin wishes to be loaded in the WebView must provide this permission
+     * in their AndroidManifest.xml.
+     */
+    public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
+
+    private static final String LOGTAG = "webkit";
+
+    private static PluginManager mInstance = null;
+
+    private final Context mContext;
+
+    private PluginManager(Context context) {
+        mContext = context;
+    }
+
+    public static synchronized PluginManager getInstance(Context context) {
+        if (mInstance == null) {
+            if (context == null) {
+                throw new IllegalStateException(
+                        "First call to PluginManager need a valid context.");
+            }
+            mInstance = new PluginManager(context);
+        }
+        return mInstance;
+    }
+
+    /**
+     * Signal the WebCore thread to refresh its list of plugins. Use this if the
+     * directory contents of one of the plugin directories has been modified and
+     * needs its changes reflecting. May cause plugin load and/or unload.
+     * 
+     * @param reloadOpenPages Set to true to reload all open pages.
+     */
+    public void refreshPlugins(boolean reloadOpenPages) {
+        BrowserFrame.sJavaBridge.obtainMessage(
+                JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages)
+                .sendToTarget();
+    }
+
+    String[] getPluginDirecoties() {
+        ArrayList<String> directories = new ArrayList<String>();
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
+                PLUGIN_ACTION), PackageManager.GET_SERVICES);
+        for (ResolveInfo info : plugins) {
+            ServiceInfo serviceInfo = info.serviceInfo;
+            if (serviceInfo == null) {
+                Log.w(LOGTAG, "Ignore bad plugin");
+                continue;
+            }
+            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);
+                continue;
+            }
+            if (pkgInfo == null) {
+                continue;
+            }
+            String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+            if (directories.contains(directory)) {
+                continue;
+            }
+            String permissions[] = pkgInfo.requestedPermissions;
+            if (permissions == null) {
+                continue;
+            }
+            boolean permissionOk = false;
+            for (String permit : permissions) {
+                if (PLUGIN_PERMISSION.equals(permit)) {
+                    permissionOk = true;
+                    break;
+                }
+            }
+            if (!permissionOk) {
+                continue;
+            }
+            Signature signatures[] = pkgInfo.signatures;
+            if (signatures == null) {
+                continue;
+            }
+            boolean signatureMatch = false;
+            for (Signature signature : signatures) {
+                // TODO: check signature against Google provided one
+                signatureMatch = true;
+                break;
+            }
+            if (!signatureMatch) {
+                continue;
+            }
+            directories.add(directory);
+        }
+        // hack for gears for now
+        String gears = mContext.getDir("plugins", 0).getPath();
+        if (!directories.contains(gears)) {
+            directories.add(gears);
+        }
+        return directories.toArray(new String[directories.size()]);
+    }
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 883aa28..93ffcdb 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -131,7 +131,6 @@
     private String          mUserAgent;
     private boolean         mUseDefaultUserAgent;
     private String          mAcceptLanguage;
-    private String          mPluginsPath = "";
     private int             mMinimumFontSize = 8;
     private int             mMinimumLogicalFontSize = 8;
     private int             mDefaultFontSize = 16;
@@ -892,15 +891,9 @@
     }
 
     /**
-     * Set a custom path to plugins used by the WebView. The client
-     * must ensure it exists before this call.
-     * @param pluginsPath String path to the directory containing plugins.
+     * TODO: need to add @Deprecated
      */
     public synchronized void setPluginsPath(String pluginsPath) {
-        if (pluginsPath != null && !pluginsPath.equals(mPluginsPath)) {
-            mPluginsPath = pluginsPath;
-            postSync();
-        }
     }
 
     /**
@@ -1001,11 +994,10 @@
     }
 
     /**
-     * Return the current path used for plugins in the WebView.
-     * @return The string path to the WebView plugins.
+     * TODO: need to add @Deprecated
      */
     public synchronized String getPluginsPath() {
-        return mPluginsPath;
+        return "";
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5b67b74..82f8a3d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2318,16 +2318,10 @@
     }
 
    /**
-    * Signal the WebCore thread to refresh its list of plugins. Use
-    * this if the directory contents of one of the plugin directories
-    * has been modified and needs its changes reflecting. May cause
-    * plugin load and/or unload.
-    * @param reloadOpenPages Set to true to reload all open pages.
+     * TODO: need to add @Deprecated
     */
     public void refreshPlugins(boolean reloadOpenPages) {
-        if (mWebViewCore != null) {
-            mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
-        }
+        PluginManager.getInstance(mContext).refreshPlugins(reloadOpenPages);
     }
 
     //-------------------------------------------------------------------------
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 1c83264..4416f1e 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -404,8 +404,6 @@
 
     private native void nativeDumpNavTree();
 
-    private native void nativeRefreshPlugins(boolean reloadOpenPages);
-    
     /**
      *  Delete text from start to end in the focused textfield. If there is no
      *  focus, or if start == end, silently fail.  If start and end are out of 
@@ -582,7 +580,7 @@
             "GET_SELECTION", // = 129;
             "WEBKIT_DRAW", // = 130;
             "SYNC_SCROLL", // = 131;
-            "REFRESH_PLUGINS", // = 132;
+            "", // = 132;
             "SPLIT_PICTURE_SET", // = 133;
             "CLEAR_CONTENT", // = 134;
             "SET_FINAL_FOCUS", // = 135;
@@ -629,7 +627,6 @@
         static final int GET_SELECTION = 129;
         static final int WEBKIT_DRAW = 130;
         static final int SYNC_SCROLL = 131;
-        static final int REFRESH_PLUGINS = 132;
         static final int SPLIT_PICTURE_SET = 133;
         static final int CLEAR_CONTENT = 134;
         
@@ -1048,10 +1045,6 @@
                             mWebkitScrollY = msg.arg2;
                             break;
 
-                        case REFRESH_PLUGINS:
-                            nativeRefreshPlugins(msg.arg1 != 0);
-                            break;
-                            
                         case SPLIT_PICTURE_SET:
                             nativeSplitContent();
                             mSplitPictureIsScheduled = false;