Add SearchBox support to preloader.

Depends on change: I0119243ed0e19e237c1f51de887af5c954f96693

Change-Id: I2a2d3ff3c9d0d79f34af4c8daee828fb4efd7519
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 2e66c84..7343f32 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -67,6 +67,7 @@
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 import android.webkit.HttpAuthHandler;
+import android.webkit.SearchBox;
 import android.webkit.SslErrorHandler;
 import android.webkit.ValueCallback;
 import android.webkit.WebChromeClient;
@@ -2182,23 +2183,37 @@
         }
     }
 
+    private Tab showPreloadedTab(final UrlData urlData) {
+        if (!urlData.isPreloaded()) {
+            return null;
+        }
+        final PreloadedTabControl tabControl = urlData.getPreloadedTab();
+        final String sbQuery = urlData.getSearchBoxQueryToSubmit();
+        if (sbQuery != null) {
+            if (!tabControl.searchBoxSubmit(sbQuery, urlData.mUrl, urlData.mHeaders)) {
+                // Could not submit query. Fallback to regular tab creation
+                tabControl.destroy();
+                return null;
+            }
+        }
+        Tab t = tabControl.getTab();
+        mTabControl.addPreloadedTab(t);
+        addTab(t);
+        setActiveTab(t);
+        return t;
+    }
+
     // open a non inconito tab with the given url data
     // and set as active tab
     public Tab openTab(UrlData urlData) {
-        if (urlData.isPreloaded()) {
-            Tab tab = urlData.getPreloadedTab();
-            tab.getWebView().clearHistory();
-            mTabControl.addPreloadedTab(tab);
-            addTab(tab);
-            setActiveTab(tab);
-            return tab;
-        } else {
-            Tab tab = createNewTab(false, true, true);
+        Tab tab = showPreloadedTab(urlData);
+        if (tab == null) {
+            tab = createNewTab(false, true, true);
             if ((tab != null) && !urlData.isEmpty()) {
                 loadUrlDataIn(tab, urlData);
             }
-            return tab;
         }
+        return tab;
     }
 
     @Override
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index a99164a..1a72a23 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -138,11 +138,6 @@
             if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false)
                   || urlData.isPreloaded()) {
                 Tab t = mController.openTab(urlData);
-                if (t == null && urlData.isPreloaded()) {
-                    Tab pre = urlData.getPreloadedTab();
-                    // TODO: check if we need to stop loading
-                    pre.destroy();
-                }
                 return;
             }
             /*
@@ -229,7 +224,8 @@
     protected static UrlData getUrlDataFromIntent(Intent intent) {
         String url = "";
         Map<String, String> headers = null;
-        Tab preloaded = null;
+        PreloadedTabControl preloaded = null;
+        String preloadedSearchBoxQuery = null;
         if (intent != null
                 && (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
             final String action = intent.getAction();
@@ -250,6 +246,8 @@
                 }
                 if (intent.hasExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID)) {
                     String id = intent.getStringExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID);
+                    preloadedSearchBoxQuery = intent.getStringExtra(
+                            PreloadRequestReceiver.EXTRA_SEARCHBOX_SETQUERY);
                     preloaded = Preloader.getInstance().getPreloadedTab(id);
                 }
             } else if (Intent.ACTION_SEARCH.equals(action)
@@ -276,7 +274,7 @@
                 }
             }
         }
-        return new UrlData(url, headers, intent, preloaded);
+        return new UrlData(url, headers, intent, preloaded, preloadedSearchBoxQuery);
     }
 
     /**
@@ -359,20 +357,23 @@
         final String mUrl;
         final Map<String, String> mHeaders;
         final Intent mVoiceIntent;
-        final Tab mPreloadedTab;
+        final PreloadedTabControl mPreloadedTab;
+        final String mSearchBoxQueryToSubmit;
 
         UrlData(String url) {
             this.mUrl = url;
             this.mHeaders = null;
             this.mVoiceIntent = null;
             this.mPreloadedTab = null;
+            this.mSearchBoxQueryToSubmit = null;
         }
 
         UrlData(String url, Map<String, String> headers, Intent intent) {
-            this(url, headers, intent, null);
+            this(url, headers, intent, null, null);
         }
 
-        UrlData(String url, Map<String, String> headers, Intent intent, Tab preloaded) {
+        UrlData(String url, Map<String, String> headers, Intent intent,
+                PreloadedTabControl preloaded, String searchBoxQueryToSubmit) {
             this.mUrl = url;
             this.mHeaders = headers;
             if (RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS
@@ -381,7 +382,8 @@
             } else {
                 this.mVoiceIntent = null;
             }
-            mPreloadedTab = preloaded;
+            this.mPreloadedTab = preloaded;
+            this.mSearchBoxQueryToSubmit = searchBoxQueryToSubmit;
         }
 
         boolean isEmpty() {
@@ -392,9 +394,13 @@
             return mPreloadedTab != null;
         }
 
-        Tab getPreloadedTab() {
+        PreloadedTabControl getPreloadedTab() {
             return mPreloadedTab;
         }
+
+        String getSearchBoxQueryToSubmit() {
+            return mSearchBoxQueryToSubmit;
+        }
     }
 
 }
diff --git a/src/com/android/browser/PreloadRequestReceiver.java b/src/com/android/browser/PreloadRequestReceiver.java
index c86d660..5176176 100644
--- a/src/com/android/browser/PreloadRequestReceiver.java
+++ b/src/com/android/browser/PreloadRequestReceiver.java
@@ -39,6 +39,7 @@
     private static final String ACTION_PRELOAD = "android.intent.action.PRELOAD";
     static final String EXTRA_PRELOAD_ID = "preload_id";
     static final String EXTRA_PRELOAD_DISCARD = "preload_discard";
+    static final String EXTRA_SEARCHBOX_SETQUERY = "searchbox_query";
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -73,8 +74,13 @@
                     }
                 }
             }
+            String sbQuery = i.getStringExtra(EXTRA_SEARCHBOX_SETQUERY);
             if (url != null) {
-                Preloader.getInstance().handlePreloadRequest(id, url, headers);
+                if (LOGD_ENABLED){
+                    Log.d(LOGTAG, "Preload request(" + id + ", " + url + ", " +
+                            headers + ", " + sbQuery + ")");
+                }
+                Preloader.getInstance().handlePreloadRequest(id, url, headers, sbQuery);
             }
         }
     }
diff --git a/src/com/android/browser/PreloadedTabControl.java b/src/com/android/browser/PreloadedTabControl.java
new file mode 100644
index 0000000..99592fb
--- /dev/null
+++ b/src/com/android/browser/PreloadedTabControl.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 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 com.android.browser;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.webkit.SearchBox;
+
+import java.util.Map;
+
+/**
+ * Class to manage the controlling of preloaded tab.
+ */
+public class PreloadedTabControl {
+    private static final boolean LOGD_ENABLED = true;//com.android.browser.Browser.LOGD_ENABLED;
+    private static final String LOGTAG = "PreloadedTabControl";
+
+    final Tab mTab;
+    private String mLastQuery;
+    private boolean mDestroyed;
+
+    public PreloadedTabControl(Tab t) {
+        mTab = t;
+    }
+
+    private void maybeSetQuery(String query, SearchBox sb) {
+        if (!TextUtils.equals(mLastQuery, query)) {
+            if (sb != null) {
+                if (LOGD_ENABLED) Log.d(LOGTAG, "Changing searchbox query to " + query);
+                sb.setVerbatim(true);
+                sb.setQuery(query);
+                sb.onchange();
+                mLastQuery = query;
+            } else {
+                if (LOGD_ENABLED) Log.d(LOGTAG, "Cannot set query: no searchbox interface");
+            }
+        }
+    }
+
+    public void setQuery(String query) {
+        maybeSetQuery(query, mTab.getWebView().getSearchBox());
+    }
+
+    public boolean searchBoxSubmit(final String query,
+            final String fallbackUrl, final Map<String, String> fallbackHeaders) {
+        final SearchBox sb = mTab.getWebView().getSearchBox();
+        if (sb == null) {
+            // no searchbox, cannot submit. Fallback to regular tab creation
+            if (LOGD_ENABLED) Log.d(LOGTAG, "No searchbox, cannot submit query");
+            return false;
+        }
+        sb.isSupported(new SearchBox.IsSupportedCallback() {
+            @Override
+            public void searchBoxIsSupported(boolean supported) {
+                if (LOGD_ENABLED) Log.d(LOGTAG, "SearchBox supported: " + supported);
+                if (mDestroyed) {
+                    if (LOGD_ENABLED) Log.d(LOGTAG, "tab has been destroyed");
+                    return;
+                }
+                if (supported) {
+                    maybeSetQuery(query, sb);
+                    if (LOGD_ENABLED) Log.d(LOGTAG, "Submitting query " + query);
+                    sb.onsubmit();
+                } else {
+                    if (LOGD_ENABLED) Log.d(LOGTAG, "SearchBox not supported; falling back");
+                    loadUrl(fallbackUrl, fallbackHeaders);
+                }
+                mTab.getWebView().clearHistory();
+            }
+        });
+        return true;
+    }
+
+    public void loadUrlIfChanged(String url, Map<String, String> headers) {
+        if (!TextUtils.equals(url, mTab.getUrl())) {
+            loadUrl(url, headers);
+        }
+    }
+
+    public void loadUrl(String url, Map<String, String> headers) {
+        if (LOGD_ENABLED) Log.d(LOGTAG, "Preloading " + url);
+        mTab.loadUrl(url, headers);
+    }
+
+    public void destroy() {
+        mDestroyed = true;
+        mTab.destroy();
+    }
+
+    public Tab getTab() {
+        return mTab;
+    }
+
+}
diff --git a/src/com/android/browser/Preloader.java b/src/com/android/browser/Preloader.java
index 5a5f687..336b77a 100644
--- a/src/com/android/browser/Preloader.java
+++ b/src/com/android/browser/Preloader.java
@@ -18,9 +18,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
-import android.util.AttributeSet;
 import android.util.Log;
-import android.webkit.WebView;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -31,7 +29,7 @@
 public class Preloader {
 
     private final static String LOGTAG = "browser.preloader";
-    private final static boolean LOGD_ENABLED = true;//com.android.browser.Browser.LOGD_ENABLED;
+    private final static boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED;
 
     private static final int PRERENDER_TIMEOUT_MILLIS = 30 * 1000; // 30s
 
@@ -76,19 +74,27 @@
         return s;
     }
 
-    public void handlePreloadRequest(String id, String url, Map<String, String> headers) {
+    public void handlePreloadRequest(String id, String url, Map<String, String> headers,
+            String searchBoxQuery) {
         PreloaderSession s = getSession(id);
         s.touch(); // reset timer
-        if (LOGD_ENABLED) Log.d(LOGTAG, "Preloading " + url);
-        s.getTab().loadUrl(url, headers);
+        PreloadedTabControl tab = s.getTabControl();
+        if (searchBoxQuery != null) {
+            tab.loadUrlIfChanged(url, headers);
+            tab.setQuery(searchBoxQuery);
+        } else {
+            tab.loadUrl(url, headers);
+        }
     }
 
     public void discardPreload(String id) {
         PreloaderSession s = takeSession(id);
         if (s != null) {
             if (LOGD_ENABLED) Log.d(LOGTAG, "Discard preload session " + id);
-            Tab t = s.getTab();
+            PreloadedTabControl t = s.getTabControl();
             t.destroy();
+        } else {
+            if (LOGD_ENABLED) Log.d(LOGTAG, "Ignored discard request " + id);
         }
     }
 
@@ -96,15 +102,15 @@
      * Return a preloaded tab, and remove it from the preloader. This is used when the
      * view is about to be displayed.
      */
-    public Tab getPreloadedTab(String id) {
+    public PreloadedTabControl getPreloadedTab(String id) {
         PreloaderSession s = takeSession(id);
         if (LOGD_ENABLED) Log.d(LOGTAG, "Showing preload session " + id + "=" + s);
-        return s == null ? null : s.getTab();
+        return s == null ? null : s.getTabControl();
     }
 
     private class PreloaderSession {
         private final String mId;
-        private final Tab mTab;
+        private final PreloadedTabControl mTabControl;
 
         private final Runnable mTimeoutTask = new Runnable(){
             @Override
@@ -115,7 +121,8 @@
 
         public PreloaderSession(String id) {
             mId = id;
-            mTab = new Tab(new PreloadController(mContext), mFactory.createWebView(false));
+            mTabControl = new PreloadedTabControl(
+                    new Tab(new PreloadController(mContext), mFactory.createWebView(false)));
             touch();
         }
 
@@ -128,8 +135,8 @@
             mHandler.postDelayed(mTimeoutTask, PRERENDER_TIMEOUT_MILLIS);
         }
 
-        public Tab getTab() {
-            return mTab;
+        public PreloadedTabControl getTabControl() {
+            return mTabControl;
         }
 
     }