Merge "Move Snapshots to own DB on sdcard"
diff --git a/res/layout/title_bar.xml b/res/layout/title_bar.xml
index 66ea1d4..9096418 100644
--- a/res/layout/title_bar.xml
+++ b/res/layout/title_bar.xml
@@ -24,11 +24,7 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/toolbar_height"
         android:orientation="horizontal"
-        android:background="@drawable/bg_urlbar"
-        android:paddingLeft="4dip"
-        android:paddingRight="4dip"
-        android:paddingTop="2dip"
-        android:paddingBottom="2dip">
+        android:background="@drawable/bg_urlbar">
         <LinearLayout
             android:id="@+id/title_bg"
             android:layout_width="0dip"
@@ -36,54 +32,58 @@
             android:layout_height="match_parent"
             android:gravity="center_vertical"
             android:orientation="horizontal">
+            <FrameLayout
+                android:id="@+id/iconcombo"
+                android:layout_width="52dip"
+                android:layout_height="match_parent"
+                style="@style/HoloButton">
+                <ImageView
+                    android:id="@+id/favicon"
+                    android:layout_width="36dip"
+                    android:layout_height="36dip"
+                    android:paddingLeft="8dip"
+                    android:paddingRight="8dip"
+                    android:layout_gravity="center_vertical" />
+                <ImageView
+                    android:id="@+id/lock"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="bottom|right"
+                    android:visibility="gone" />
+            </FrameLayout>
             <ImageView
-                android:id="@+id/favicon"
-                android:layout_width="20dip"
-                android:layout_height="20dip" />
-            <ImageView
-                android:id="@+id/lock"
+                android:id="@+id/stop"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginLeft="2dip"
-                android:visibility="gone" />
+                android:layout_gravity="center_vertical"
+                android:src="@drawable/ic_stop_holo_dark"
+                style="@style/HoloButton" />
             <com.android.browser.UrlInputView
                 android:id="@+id/url"
                 android:focusable="true"
                 android:layout_width="0dip"
                 android:layout_weight="1.0"
                 android:layout_height="match_parent"
-                android:layout_marginLeft="2dip"
-                android:paddingLeft="4dip"
-                android:paddingRight="4dip"
-                android:background="@*android:drawable/edit_text_holo_dark"
+                android:fadingEdge="horizontal"
+                android:fadingEdgeLength="24dip"
                 android:textAppearance="?android:attr/textAppearanceMedium"
                 android:hint="@string/search_hint"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:lines="1"
                 android:scrollHorizontally="true"
-                android:inputType="textUri"
+                android:inputType="text"
                 android:imeOptions="actionGo"
-                style="@style/Suggestions" />
+                style="@style/Suggestions"
+                android:background="@null" />
+            <ImageView
+                android:id="@+id/voice"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:src="@drawable/ic_voice_search_holo_dark"
+                style="@style/HoloButton"
+                android:visibility="gone" />
         </LinearLayout>
-        <ImageView
-            android:id="@+id/voice"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:src="@drawable/ic_voice_search_holo_dark"
-            android:visibility="gone" />
-        <ImageView
-            android:id="@+id/stop"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:src="@drawable/ic_stop_holo_dark" />
-        <ImageButton
-            android:id="@+id/forward"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:src="@drawable/ic_forward_holo_dark"
-            style="@style/HoloButton" />
         <ImageButton
             android:id="@+id/tab_switcher"
             android:layout_width="wrap_content"
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index d02a843..003d2d8 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;
         }
 
     }
diff --git a/src/com/android/browser/TitleBarBase.java b/src/com/android/browser/TitleBarBase.java
index ae11038..de44306 100644
--- a/src/com/android/browser/TitleBarBase.java
+++ b/src/com/android/browser/TitleBarBase.java
@@ -493,13 +493,6 @@
     }
 
     protected void setFocusState(boolean focus) {
-        if (focus) {
-            updateSearchMode(false);
-        }
-    }
-
-    protected void updateSearchMode(boolean userEdited) {
-        setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText()));
     }
 
     protected void setSearchMode(boolean voiceSearchEnabled) {}
@@ -523,8 +516,6 @@
     @Override
     public void onTextChanged(String newText) {
         if (mUrlInput.hasFocus()) {
-            // check if input field is empty and adjust voice search state
-            updateSearchMode(true);
             // clear voice mode when user types
             setInVoiceMode(false, null);
         }
diff --git a/src/com/android/browser/TitleBarPhone.java b/src/com/android/browser/TitleBarPhone.java
index 528ea43..f41eca7 100644
--- a/src/com/android/browser/TitleBarPhone.java
+++ b/src/com/android/browser/TitleBarPhone.java
@@ -16,8 +16,6 @@
 
 package com.android.browser;
 
-import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
@@ -29,9 +27,11 @@
 import android.view.View.OnFocusChangeListener;
 import android.webkit.WebView;
 import android.widget.FrameLayout;
-import android.widget.ImageButton;
 import android.widget.ImageView;
 
+import com.android.browser.UrlInputView.StateListener;
+import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
+
 import java.util.List;
 
 /**
@@ -39,16 +39,17 @@
  * browser.
  */
 public class TitleBarPhone extends TitleBarBase implements OnFocusChangeListener,
-        OnClickListener, TextChangeWatcher {
+        OnClickListener, TextChangeWatcher, StateListener {
 
     private Activity mActivity;
     private ImageView mStopButton;
     private ImageView mVoiceButton;
-    private boolean mHasLockIcon;
-    private ImageButton mForward;
     private Drawable mStopDrawable;
     private Drawable mRefreshDrawable;
     private View mTabSwitcher;
+    private View mComboIcon;
+    private View mTitleContainer;
+    private Drawable mTextfieldBgDrawable;
 
     public TitleBarPhone(Activity activity, UiController controller, PhoneUi ui,
             FrameLayout parent) {
@@ -66,16 +67,18 @@
         mStopButton.setOnClickListener(this);
         mVoiceButton = (ImageView) findViewById(R.id.voice);
         mVoiceButton.setOnClickListener(this);
-        mForward = (ImageButton) findViewById(R.id.forward);
-        mForward.setOnClickListener(this);
         mTabSwitcher = findViewById(R.id.tab_switcher);
         mTabSwitcher.setOnClickListener(this);
+        mComboIcon = findViewById(R.id.iconcombo);
+        mTitleContainer = findViewById(R.id.title_bg);
         setFocusState(false);
         Resources res = context.getResources();
         mStopDrawable = res.getDrawable(R.drawable.ic_stop_holo_dark);
         mRefreshDrawable = res.getDrawable(R.drawable.ic_refresh_holo_dark);
-        setUaSwitcher(mFavicon);
+        mTextfieldBgDrawable = res.getDrawable(R.drawable.textfield_active_holo_dark);
+        setUaSwitcher(mComboIcon);
         mUrlInput.setContainer(this);
+        mUrlInput.setStateListener(this);
     }
 
     @Override
@@ -99,29 +102,23 @@
     }
 
     @Override
-    protected void setFocusState(boolean focus) {
-        super.setFocusState(focus);
-        if (focus) {
-            mHasLockIcon = (mLockIcon.getVisibility() == View.VISIBLE);
-            mLockIcon.setVisibility(View.GONE);
-            mStopButton.setVisibility(View.GONE);
-            mVoiceButton.setVisibility(View.VISIBLE);
-        } else {
-            mLockIcon.setVisibility(mHasLockIcon ? View.VISIBLE : View.GONE);
-            mStopButton.setVisibility(View.VISIBLE);
-            mVoiceButton.setVisibility(View.GONE);
-        }
-    }
-
-    @Override
     void setProgress(int progress) {
         super.setProgress(progress);
         if (progress == 100) {
+            mStopButton.setVisibility(View.GONE);
             mStopButton.setImageDrawable(mRefreshDrawable);
-        } else if (mStopButton.getDrawable() != mStopDrawable) {
-            mStopButton.setImageDrawable(mStopDrawable);
+            if (!isEditingUrl()) {
+                mComboIcon.setVisibility(View.VISIBLE);
+            }
+        } else {
+            if (mStopButton.getDrawable() != mStopDrawable) {
+                mStopButton.setImageDrawable(mStopDrawable);
+                if (mStopButton.getVisibility() != View.VISIBLE) {
+                    mComboIcon.setVisibility(View.GONE);
+                    mStopButton.setVisibility(View.VISIBLE);
+                }
+            }
         }
-        updateNavigationState();
     }
 
     /**
@@ -138,7 +135,6 @@
                 mUrlInput.setText(title);
             }
             mUrlInput.setSelection(0);
-            updateNavigationState();
         }
     }
 
@@ -160,16 +156,12 @@
             } else {
                 WebView web = mBaseUi.getWebView();
                 if (web != null) {
+                    stopEditingUrl();
                     web.reload();
                 }
             }
         } else if (v == mVoiceButton) {
             mUiController.startVoiceSearch();
-        } else if (v == mForward) {
-            WebView web = mBaseUi.getWebView();
-            if (web != null) {
-                web.goForward();
-            }
         } else if (v == mTabSwitcher) {
             mBaseUi.onMenuKey();
         } else {
@@ -177,10 +169,30 @@
         }
     }
 
-    private void updateNavigationState() {
-        WebView web = mBaseUi.getWebView();
-        if (web != null) {
-          mForward.setVisibility(web.canGoForward() ? View.VISIBLE : View.GONE);
+    @Override
+    public void onStateChanged(int state) {
+        switch(state) {
+        case StateListener.STATE_NORMAL:
+            mComboIcon.setVisibility(View.VISIBLE);
+            mStopButton.setVisibility(View.GONE);
+            setSearchMode(false);
+            mTabSwitcher.setVisibility(View.VISIBLE);
+            mTitleContainer.setBackgroundDrawable(null);
+            break;
+        case StateListener.STATE_HIGHLIGHTED:
+            mComboIcon.setVisibility(View.GONE);
+            mStopButton.setVisibility(View.VISIBLE);
+            setSearchMode(true);
+            mTabSwitcher.setVisibility(View.GONE);
+            mTitleContainer.setBackgroundDrawable(mTextfieldBgDrawable);
+            break;
+        case StateListener.STATE_EDITED:
+            mComboIcon.setVisibility(View.GONE);
+            mStopButton.setVisibility(View.GONE);
+            setSearchMode(false);
+            mTabSwitcher.setVisibility(View.GONE);
+            mTitleContainer.setBackgroundDrawable(mTextfieldBgDrawable);
+            break;
         }
     }
 
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index 3d4d2ec..6aed86c 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -218,7 +218,6 @@
         mStopButton.setImageDrawable(mReloadDrawable);
     }
 
-    @Override
     protected void updateSearchMode(boolean userEdited) {
         setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText()));
     }
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
index 7545e6a..8b5c292 100644
--- a/src/com/android/browser/UrlInputView.java
+++ b/src/com/android/browser/UrlInputView.java
@@ -16,14 +16,6 @@
 
 package com.android.browser;
 
-import com.android.browser.SuggestionsAdapter.CompletionListener;
-import com.android.browser.SuggestionsAdapter.SuggestItem;
-import com.android.browser.UI.DropdownChangeListener;
-import com.android.browser.autocomplete.SuggestiveAutoCompleteTextView;
-import com.android.browser.search.SearchEngine;
-import com.android.browser.search.SearchEngineInfo;
-import com.android.browser.search.SearchEngines;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
@@ -32,6 +24,7 @@
 import android.util.AttributeSet;
 import android.util.Patterns;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -40,6 +33,15 @@
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
+import com.android.browser.SuggestionsAdapter.CompletionListener;
+import com.android.browser.SuggestionsAdapter.SuggestItem;
+import com.android.browser.UI.DropdownChangeListener;
+import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
+import com.android.browser.autocomplete.SuggestiveAutoCompleteTextView;
+import com.android.browser.search.SearchEngine;
+import com.android.browser.search.SearchEngineInfo;
+import com.android.browser.search.SearchEngines;
+
 import java.util.List;
 
 /**
@@ -48,13 +50,20 @@
  */
 public class UrlInputView extends SuggestiveAutoCompleteTextView
         implements OnEditorActionListener,
-        CompletionListener, OnItemClickListener {
-
+        CompletionListener, OnItemClickListener, TextChangeWatcher {
 
     static final String TYPED = "browser-type";
     static final String SUGGESTED = "browser-suggest";
     static final String VOICE = "voice-search";
 
+    static interface StateListener {
+        static final int STATE_NORMAL = 0;
+        static final int STATE_HIGHLIGHTED = 1;
+        static final int STATE_EDITED = 2;
+
+        public void onStateChanged(int state);
+    }
+
     private UrlInputListener   mListener;
     private InputMethodManager mInputManager;
     private SuggestionsAdapter mAdapter;
@@ -64,6 +73,9 @@
     private boolean mNeedsUpdate;
     private DropdownChangeListener mDropdownListener;
 
+    private int mState;
+    private StateListener mStateListener;
+
     public UrlInputView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         init(context);
@@ -90,6 +102,7 @@
         setOnItemClickListener(this);
         mNeedsUpdate = false;
         mDropdownListener = null;
+        addQueryTextWatcher(this);
 
         mAdapter.registerDataSetObserver(new DataSetObserver() {
             @Override
@@ -105,6 +118,32 @@
                 dispatchChange();
             }
         });
+        mState = StateListener.STATE_NORMAL;
+    }
+
+    protected void onFocusChanged(boolean focused, int direction, Rect prevRect) {
+        super.onFocusChanged(focused, direction, prevRect);
+        if (focused) {
+            if (hasSelection()) {
+                changeState(StateListener.STATE_HIGHLIGHTED);
+            } else {
+                changeState(StateListener.STATE_EDITED);
+            }
+        } else {
+            // reset the selection state
+            changeState(StateListener.STATE_NORMAL);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent evt) {
+        boolean hasSelection = hasSelection();
+        boolean res = super.onTouchEvent(evt);
+        if ((MotionEvent.ACTION_DOWN == evt.getActionMasked())
+              && hasSelection) {
+            changeState(StateListener.STATE_EDITED);
+        }
+        return res;
     }
 
     /**
@@ -135,6 +174,19 @@
         mListener = listener;
     }
 
+    public void setStateListener(StateListener listener) {
+        mStateListener = listener;
+        // update listener
+        changeState(mState);
+    }
+
+    private void changeState(int newState) {
+        mState = newState;
+        if (mStateListener != null) {
+            mStateListener.onStateChanged(mState);
+        }
+    }
+
     void setVoiceResults(List<String> voiceResults) {
         mAdapter.setVoiceResults(voiceResults);
     }
@@ -305,4 +357,12 @@
     public boolean requestRectangleOnScreen(Rect rect, boolean immediate) {
         return false;
     }
+
+    @Override
+    public void onTextChanged(String newText) {
+        if (StateListener.STATE_HIGHLIGHTED == mState) {
+            changeState(StateListener.STATE_EDITED);
+        }
+    }
+
 }