Merge "Launch intents to open/delete downloads, and handle them in the browser."
diff --git a/Android.mk b/Android.mk
index 92fcb1c..b9a46f4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := google-framework
+LOCAL_STATIC_JAVA_LIBRARIES := gsf-client
 
 LOCAL_SRC_FILES := \
         $(call all-subdir-java-files) \
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index 33396a0..f32866d 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -50,7 +50,7 @@
 
 import com.android.common.Patterns;
 
-import com.google.android.providers.GoogleSettings.Partner;
+import com.google.android.gsf.GoogleSettingsContract.Partner;
 
 import java.io.File;
 import java.io.FilenameFilter;
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 941b28b..1e282c6 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -17,7 +17,7 @@
 
 package com.android.browser;
 
-import com.google.android.providers.GoogleSettings.Partner;
+import com.google.android.gsf.GoogleSettingsContract.Partner;
 
 import android.app.ActivityManager;
 import android.content.ContentResolver;
diff --git a/src/com/android/browser/ErrorConsoleView.java b/src/com/android/browser/ErrorConsoleView.java
index 56f663b..0f87cb5 100644
--- a/src/com/android/browser/ErrorConsoleView.java
+++ b/src/com/android/browser/ErrorConsoleView.java
@@ -18,11 +18,13 @@
 
 import android.content.Context;
 import android.database.DataSetObserver;
+import android.graphics.Color;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.webkit.ConsoleMessage;
 import android.webkit.WebView;
 import android.widget.Button;
 import android.widget.EditText;
@@ -55,7 +57,7 @@
     // Before we've been asked to display the console, cache any messages that should
     // be added to the console. Then when we do display the console, add them to the view
     // then.
-    private Vector<ErrorConsoleMessage> mErrorMessageCache;
+    private Vector<ConsoleMessage> mErrorMessageCache;
 
     public ErrorConsoleView(Context context) {
         super(context);
@@ -108,8 +110,8 @@
 
         // Add any cached messages to the list now that we've assembled the view.
         if (mErrorMessageCache != null) {
-            for (ErrorConsoleMessage msg : mErrorMessageCache) {
-                mErrorList.addErrorMessage(msg.getMessage(), msg.getSourceID(), msg.getLineNumber());
+            for (ConsoleMessage msg : mErrorMessageCache) {
+                mErrorList.addErrorMessage(msg);
             }
             mErrorMessageCache.clear();
         }
@@ -120,14 +122,14 @@
     /**
      * Adds a message to the set of messages the console uses.
      */
-    public void addErrorMessage(String msg, String sourceId, int lineNumber) {
+    public void addErrorMessage(ConsoleMessage consoleMessage) {
         if (mSetupComplete) {
-            mErrorList.addErrorMessage(msg, sourceId, lineNumber);
+            mErrorList.addErrorMessage(consoleMessage);
         } else {
             if (mErrorMessageCache == null) {
-                mErrorMessageCache = new Vector<ErrorConsoleMessage>();
+                mErrorMessageCache = new Vector<ConsoleMessage>();
             }
-            mErrorMessageCache.add(new ErrorConsoleMessage(msg, sourceId, lineNumber));
+            mErrorMessageCache.add(consoleMessage);
         }
     }
 
@@ -215,8 +217,8 @@
             setAdapter(mConsoleMessages);
         }
 
-        public void addErrorMessage(String msg, String sourceId, int lineNumber) {
-            mConsoleMessages.add(msg, sourceId, lineNumber);
+        public void addErrorMessage(ConsoleMessage consoleMessage) {
+            mConsoleMessages.add(consoleMessage);
             setSelection(mConsoleMessages.getCount());
         }
 
@@ -231,11 +233,11 @@
         private class ErrorConsoleMessageList extends android.widget.BaseAdapter
                 implements android.widget.ListAdapter {
 
-            private Vector<ErrorConsoleMessage> mMessages;
+            private Vector<ConsoleMessage> mMessages;
             private LayoutInflater mInflater;
 
             public ErrorConsoleMessageList(Context context) {
-                mMessages = new Vector<ErrorConsoleMessage>();
+                mMessages = new Vector<ConsoleMessage>();
                 mInflater = (LayoutInflater)context.getSystemService(
                         Context.LAYOUT_INFLATER_SERVICE);
             }
@@ -243,8 +245,8 @@
             /**
              * Add a new message to the list and update the View.
              */
-            public void add(String msg, String sourceID, int lineNumber) {
-                mMessages.add(new ErrorConsoleMessage(msg, sourceID, lineNumber));
+            public void add(ConsoleMessage consoleMessage) {
+                mMessages.add(consoleMessage);
                 notifyDataSetChanged();
             }
 
@@ -288,7 +290,7 @@
              */
             public View getView(int position, View convertView, ViewGroup parent) {
                 View view;
-                ErrorConsoleMessage error = mMessages.get(position);
+                ConsoleMessage error = mMessages.get(position);
 
                 if (error == null) {
                     return null;
@@ -302,38 +304,26 @@
 
                 TextView headline = (TextView) view.findViewById(android.R.id.text1);
                 TextView subText = (TextView) view.findViewById(android.R.id.text2);
-                headline.setText(error.getSourceID() + ":" + error.getLineNumber());
-                subText.setText(error.getMessage());
+                headline.setText(error.sourceId() + ":" + error.lineNumber());
+                subText.setText(error.message());
+                switch (error.messageLevel()) {
+                    case ERROR:
+                        subText.setTextColor(Color.RED);
+                        break;
+                    case WARNING:
+                        // Orange
+                        subText.setTextColor(Color.rgb(255,192,0));
+                        break;
+                    case TIP:
+                        subText.setTextColor(Color.BLUE);
+                        break;
+                    default:
+                        subText.setTextColor(Color.LTGRAY);
+                        break;
+                }
                 return view;
             }
 
         }
     }
-
-    /**
-     * This class holds the data for a single error message in the console.
-     */
-    private static class ErrorConsoleMessage {
-        private String mMessage;
-        private String mSourceID;
-        private int mLineNumber;
-
-        public ErrorConsoleMessage(String msg, String sourceID, int lineNumber) {
-            mMessage = msg;
-            mSourceID = sourceID;
-            mLineNumber = lineNumber;
-        }
-
-        public String getMessage() {
-            return mMessage;
-        }
-
-        public String getSourceID() {
-            return mSourceID;
-        }
-
-        public int getLineNumber() {
-            return mLineNumber;
-        }
-    }
 }
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index c939a13..3c8f5ba 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -46,6 +46,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.webkit.ConsoleMessage;
 import android.webkit.CookieSyncManager;
 import android.webkit.GeolocationPermissions;
 import android.webkit.HttpAuthHandler;
@@ -70,6 +71,11 @@
 class Tab {
     // Log Tag
     private static final String LOGTAG = "Tab";
+    // Special case the logtag for messages for the Console to make it easier to
+    // filter them and match the logtag used for these messages in older versions
+    // of the browser.
+    private static final String CONSOLE_LOGTAG = "browser";
+
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
@@ -173,47 +179,86 @@
      *      results when reusing the old results.
      */
     /* package */ void activateVoiceSearchMode(Intent intent) {
+        int index = 0;
         ArrayList<String> results = intent.getStringArrayListExtra(
                     RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_STRINGS);
-        ArrayList<String> urls = intent.getStringArrayListExtra(
-                    RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_URLS);
         if (results != null) {
+            ArrayList<String> urls = intent.getStringArrayListExtra(
+                        RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_URLS);
+            ArrayList<String> htmls = intent.getStringArrayListExtra(
+                        RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_HTML);
+            ArrayList<String> baseUrls = intent.getStringArrayListExtra(
+                        RecognizerResultsIntent
+                        .EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS);
             // This tab is now entering voice search mode for the first time, or
             // a new voice search was done.
-            if (urls == null || results.size() != urls.size()) {
+            int size = results.size();
+            if (urls == null || size != urls.size()) {
                 throw new AssertionError("improper extras passed in Intent");
             }
-            mVoiceSearchData = new VoiceSearchData(results, urls);
+            if (htmls == null || htmls.size() != size || baseUrls == null ||
+                    (baseUrls.size() != size && baseUrls.size() != 1)) {
+                // If either of these arrays are empty/incorrectly sized, ignore
+                // them.
+                htmls = null;
+                baseUrls = null;
+            }
+            mVoiceSearchData = new VoiceSearchData(results, urls, htmls,
+                    baseUrls);
         } else {
             String extraData = intent.getStringExtra(
                     SearchManager.EXTRA_DATA_KEY);
             if (extraData != null) {
-                mVoiceSearchData.mLastVoiceSearchIndex
-                        = Integer.parseInt(extraData);
-                if (mVoiceSearchData.mLastVoiceSearchIndex
-                        >= mVoiceSearchData.mVoiceSearchResults.size()) {
+                index = Integer.parseInt(extraData);
+                if (index >= mVoiceSearchData.mVoiceSearchResults.size()) {
                     throw new AssertionError("index must be less than "
                             + " size of mVoiceSearchResults");
                 }
             }
         }
         mVoiceSearchData.mLastVoiceSearchTitle
-                = mVoiceSearchData.mVoiceSearchResults.get(mVoiceSearchData.
-                mLastVoiceSearchIndex);
+                = mVoiceSearchData.mVoiceSearchResults.get(index);
         if (mInForeground) {
             mActivity.showVoiceTitleBar(mVoiceSearchData.mLastVoiceSearchTitle);
         }
+        if (mVoiceSearchData.mVoiceSearchHtmls != null) {
+            // When index was found it was already ensured that it was valid
+            String uriString = mVoiceSearchData.mVoiceSearchHtmls.get(index);
+            if (uriString != null) {
+                Uri dataUri = Uri.parse(uriString);
+                if (RecognizerResultsIntent.URI_SCHEME_INLINE.equals(
+                        dataUri.getScheme())) {
+                    // If there is only one base URL, use it.  If there are
+                    // more, there will be one for each index, so use the base
+                    // URL corresponding to the index.
+                    String baseUrl = mVoiceSearchData.mVoiceSearchBaseUrls.get(
+                            mVoiceSearchData.mVoiceSearchBaseUrls.size() > 1 ?
+                            index : 0);
+                    mVoiceSearchData.mLastVoiceSearchUrl = baseUrl;
+                    mMainView.loadDataWithBaseURL(baseUrl,
+                            uriString.substring(RecognizerResultsIntent
+                            .URI_SCHEME_INLINE.length() + 1), "text/html",
+                            "utf-8", baseUrl);
+                    return;
+                }
+            }
+        }
         mVoiceSearchData.mLastVoiceSearchUrl
-                = mVoiceSearchData.mVoiceSearchUrls.get(mVoiceSearchData.
-                mLastVoiceSearchIndex);
+                = mVoiceSearchData.mVoiceSearchUrls.get(index);
+        if (null == mVoiceSearchData.mLastVoiceSearchUrl) {
+            mVoiceSearchData.mLastVoiceSearchUrl = mActivity.smartUrlFilter(
+                    mVoiceSearchData.mLastVoiceSearchTitle);
+        }
         mMainView.loadUrl(mVoiceSearchData.mLastVoiceSearchUrl);
     }
     /* package */ static class VoiceSearchData {
         public VoiceSearchData(ArrayList<String> results,
-                ArrayList<String> urls) {
+                ArrayList<String> urls, ArrayList<String> htmls,
+                ArrayList<String> baseUrls) {
             mVoiceSearchResults = results;
             mVoiceSearchUrls = urls;
-            mLastVoiceSearchIndex = 0;
+            mVoiceSearchHtmls = htmls;
+            mVoiceSearchBaseUrls = baseUrls;
         }
         /*
          * ArrayList of suggestions to be displayed when opening the
@@ -226,9 +271,20 @@
          */
         public ArrayList<String> mVoiceSearchUrls;
         /*
+         * ArrayList holding content to load for each item in
+         * mVoiceSearchResults.
+         */
+        public ArrayList<String> mVoiceSearchHtmls;
+        /*
+         * ArrayList holding base urls for the items in mVoiceSearchResults.
+         * If non null, this will either have the same size as
+         * mVoiceSearchResults or have a size of 1, in which case all will use
+         * the same base url
+         */
+        public ArrayList<String> mVoiceSearchBaseUrls;
+        /*
          * The last url provided by voice search.  Used for comparison to see if
-         * we are going to a page by some method besides voice search.  Only
-         * meaningful in voice search mode.
+         * we are going to a page by some method besides voice search.
          */
         public String mLastVoiceSearchUrl;
         /**
@@ -236,12 +292,6 @@
          * when switching tabs.
          */
         public String mLastVoiceSearchTitle;
-        /*
-         * The index into mVoiceSearchResults and mVoiceSearchUrls of the last
-         * voice search performed. Stored so it can be used to index into
-         * mVoiceSearchUrls to determine the url in getUrlDataFromIntent.
-         */
-        public int mLastVoiceSearchIndex;
     }
 
     // Container class for the next error dialog that needs to be displayed
@@ -939,24 +989,43 @@
         /* Adds a JavaScript error message to the system log and if the JS
          * console is enabled in the about:debug options, to that console
          * also.
-         * @param message The error message to report.
-         * @param lineNumber The line number of the error.
-         * @param sourceID The name of the source file that caused the error.
+         * @param consoleMessage the message object.
          */
         @Override
-        public void onConsoleMessage(String message, int lineNumber,
-                String sourceID) {
+        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
             if (mInForeground) {
                 // call getErrorConsole(true) so it will create one if needed
                 ErrorConsoleView errorConsole = getErrorConsole(true);
-                errorConsole.addErrorMessage(message, sourceID, lineNumber);
+                errorConsole.addErrorMessage(consoleMessage);
                 if (mActivity.shouldShowErrorConsole()
                         && errorConsole.getShowState() != ErrorConsoleView.SHOW_MAXIMIZED) {
                     errorConsole.showConsole(ErrorConsoleView.SHOW_MINIMIZED);
                 }
             }
-            Log.w(LOGTAG, "Console: " + message + " " + sourceID + ":"
-                    + lineNumber);
+
+            String message = "Console: " + consoleMessage.message() + " "
+                    + consoleMessage.sourceId() +  ":"
+                    + consoleMessage.lineNumber();
+
+            switch (consoleMessage.messageLevel()) {
+                case TIP:
+                    Log.v(CONSOLE_LOGTAG, message);
+                    break;
+                case LOG:
+                    Log.i(CONSOLE_LOGTAG, message);
+                    break;
+                case WARNING:
+                    Log.w(CONSOLE_LOGTAG, message);
+                    break;
+                case ERROR:
+                    Log.e(CONSOLE_LOGTAG, message);
+                    break;
+                case DEBUG:
+                    Log.d(CONSOLE_LOGTAG, message);
+                    break;
+            }
+
+            return true;
         }
 
         /**