Merge "Load WebView from one out of a list of packages."
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index cafe053..4d8dce1 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -76,9 +76,54 @@
     private static boolean sAddressSpaceReserved = false;
     private static PackageInfo sPackageInfo;
 
+    /** @hide */
+    public static String[] getWebViewPackageNames() {
+        return AppGlobals.getInitialApplication().getResources().getStringArray(
+                com.android.internal.R.array.config_webViewPackageNames);
+    }
+
+    // TODO (gsennton) remove when committing webview xts test change
     public static String getWebViewPackageName() {
-        return AppGlobals.getInitialApplication().getString(
-                com.android.internal.R.string.config_webViewPackageName);
+        String[] webViewPackageNames = getWebViewPackageNames();
+        return webViewPackageNames[webViewPackageNames.length-1];
+    }
+
+    /**
+     * Return the package info of the first package in the webview priority list that contains
+     * webview.
+     *
+     * @hide
+     */
+    public static PackageInfo findPreferredWebViewPackage() {
+        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+
+        for (String packageName : getWebViewPackageNames()) {
+            try {
+                PackageInfo packageInfo = pm.getPackageInfo(packageName,
+                    PackageManager.GET_META_DATA);
+                ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+
+                // If the correct flag is set the package contains webview.
+                if (getWebViewLibrary(applicationInfo) != null) {
+                    return packageInfo;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+            }
+        }
+        throw new AndroidRuntimeException("Could not find a loadable WebView package");
+    }
+
+    private static ApplicationInfo getWebViewApplicationInfo() {
+        if (sPackageInfo == null)
+            return findPreferredWebViewPackage().applicationInfo;
+        else
+            return sPackageInfo.applicationInfo;
+    }
+
+    private static String getWebViewLibrary(ApplicationInfo ai) {
+        if (ai.metaData != null)
+            return ai.metaData.getString("com.android.webview.WebViewLibrary");
+        return null;
     }
 
     public static PackageInfo getLoadedPackageInfo() {
@@ -99,6 +144,11 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
+                // First fetch the package info so we can log the webview package version.
+                sPackageInfo = findPreferredWebViewPackage();
+                Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
+                    sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
+
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
                 loadNativeLibrary();
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
@@ -137,15 +187,10 @@
     private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
         Application initialApplication = AppGlobals.getInitialApplication();
         try {
-            // First fetch the package info so we can log the webview package version.
-            String packageName = getWebViewPackageName();
-            sPackageInfo = initialApplication.getPackageManager().getPackageInfo(packageName, 0);
-            Log.i(LOGTAG, "Loading " + packageName + " version " + sPackageInfo.versionName +
-                          " (code " + sPackageInfo.versionCode + ")");
-
             // Construct a package context to load the Java code into the current app.
-            Context webViewContext = initialApplication.createPackageContext(packageName,
-                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+            Context webViewContext = initialApplication.createPackageContext(
+                sPackageInfo.packageName,
+                Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
             initialApplication.getAssets().addAssetPath(
                     webViewContext.getApplicationInfo().sourceDir);
             ClassLoader clazzLoader = webViewContext.getClassLoader();
@@ -272,10 +317,8 @@
 
     private static String[] getWebViewNativeLibraryPaths()
             throws PackageManager.NameNotFoundException {
-        final String NATIVE_LIB_FILE_NAME = "libwebviewchromium.so";
-
-        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-        ApplicationInfo ai = pm.getApplicationInfo(getWebViewPackageName(), 0);
+        ApplicationInfo ai = getWebViewApplicationInfo();
+        final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
 
         String path32;
         String path64;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8c78e74..8336058 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1962,8 +1962,10 @@
         string that's stored in 8-bit unpacked format) characters.-->
     <bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
 
-    <!-- Package name providing WebView implementation. -->
-    <string name="config_webViewPackageName" translatable="false">com.android.webview</string>
+    <!-- List of package names (ordered by preference) providing WebView implementations. -->
+    <string-array name="config_webViewPackageNames" translatable="false">
+      <item>com.android.webview</item>
+    </string-array>
 
     <!-- If EMS is not supported, framework breaks down EMS into single segment SMS
          and adds page info " x/y". This config is used to set which carrier doesn't
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5b1cb5..f6471e1 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1995,7 +1995,7 @@
   <java-symbol type="attr" name="actionModeWebSearchDrawable" />
   <java-symbol type="string" name="websearch" />
   <java-symbol type="drawable" name="ic_media_video_poster" />
-  <java-symbol type="string" name="config_webViewPackageName" />
+  <java-symbol type="array" name="config_webViewPackageNames" />
 
   <!-- From SubtitleView -->
   <java-symbol type="dimen" name="subtitle_corner_radius" />
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index d4c5f87..ac79b36 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -40,6 +40,8 @@
     private boolean mRelroReady32Bit = false;
     private boolean mRelroReady64Bit = false;
 
+    private String oldWebViewPackageName = null;
+
     private BroadcastReceiver mWebViewUpdatedReceiver;
 
     public WebViewUpdateService(Context context) {
@@ -51,9 +53,22 @@
         mWebViewUpdatedReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    String webviewPackage = "package:" + WebViewFactory.getWebViewPackageName();
-                    if (webviewPackage.equals(intent.getDataString())) {
-                        onWebViewUpdateInstalled();
+
+                    for (String packageName : WebViewFactory.getWebViewPackageNames()) {
+                        String webviewPackage = "package:" + packageName;
+
+                        if (webviewPackage.equals(intent.getDataString())) {
+                            String usedPackageName =
+                                WebViewFactory.findPreferredWebViewPackage().packageName;
+                            // Only trigger update actions if the updated package is the one that
+                            // will be used, or the one that was in use before the update.
+                            if (packageName.equals(usedPackageName) ||
+                                    packageName.equals(oldWebViewPackageName)) {
+                                onWebViewUpdateInstalled();
+                                oldWebViewPackageName = usedPackageName;
+                            }
+                            return;
+                        }
                     }
                 }
         };