Implemented new voice search hints UX.

The voice search hints now replace the query text box in the widget. While a voice search hint is displayed, the behaviour of the widget is chanhed slightly:
- Click the hint launches voice search help (if available), else just voice search.
- The corpus selector changes its behaviour such that it hides the hint. The arrow is removed to indicate that it no longer behaves as a selector.

Bug: 2503349

Change-Id: I1e3bf36c930cbeb2d754893c08ce0bf202798cda
diff --git a/res/drawable-hdpi/corpus_indicator_arrow.9.png b/res/drawable-hdpi/corpus_indicator_arrow.9.png
new file mode 100644
index 0000000..e1788bd
--- /dev/null
+++ b/res/drawable-hdpi/corpus_indicator_arrow.9.png
Binary files differ
diff --git a/res/drawable-hdpi/corpus_indicator_bg_default.png b/res/drawable-hdpi/corpus_indicator_bg_default.png
deleted file mode 100644
index 2b4a7da..0000000
--- a/res/drawable-hdpi/corpus_indicator_bg_default.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/corpus_indicator_bg_focused.png b/res/drawable-hdpi/corpus_indicator_bg_focused.png
index b6b5d45..e03fc55 100644
--- a/res/drawable-hdpi/corpus_indicator_bg_focused.png
+++ b/res/drawable-hdpi/corpus_indicator_bg_focused.png
Binary files differ
diff --git a/res/drawable-hdpi/corpus_indicator_bg_pressed.png b/res/drawable-hdpi/corpus_indicator_bg_pressed.png
index efcc6ee..39a172e 100644
--- a/res/drawable-hdpi/corpus_indicator_bg_pressed.png
+++ b/res/drawable-hdpi/corpus_indicator_bg_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/corpus_indicator_blank.9.png b/res/drawable-hdpi/corpus_indicator_blank.9.png
new file mode 100644
index 0000000..db20e7a
--- /dev/null
+++ b/res/drawable-hdpi/corpus_indicator_blank.9.png
Binary files differ
diff --git a/res/drawable-hdpi/voice_search_hint_bg.9.png b/res/drawable-hdpi/voice_search_hint_bg.9.png
deleted file mode 100644
index 438c172..0000000
--- a/res/drawable-hdpi/voice_search_hint_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/voice_search_hint_bg_normal.9.png b/res/drawable-hdpi/voice_search_hint_bg_normal.9.png
new file mode 100644
index 0000000..414203c
--- /dev/null
+++ b/res/drawable-hdpi/voice_search_hint_bg_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/voice_search_hint_bg_pressed.9.png b/res/drawable-hdpi/voice_search_hint_bg_pressed.9.png
new file mode 100644
index 0000000..067b12b
--- /dev/null
+++ b/res/drawable-hdpi/voice_search_hint_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/voice_search_hint_bg_selected.9.png b/res/drawable-hdpi/voice_search_hint_bg_selected.9.png
new file mode 100644
index 0000000..f60a8cc
--- /dev/null
+++ b/res/drawable-hdpi/voice_search_hint_bg_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi/corpus_indicator_arrow.9.png b/res/drawable-mdpi/corpus_indicator_arrow.9.png
new file mode 100644
index 0000000..9073dd2
--- /dev/null
+++ b/res/drawable-mdpi/corpus_indicator_arrow.9.png
Binary files differ
diff --git a/res/drawable-mdpi/corpus_indicator_bg_default.png b/res/drawable-mdpi/corpus_indicator_bg_default.png
deleted file mode 100644
index c5c97b3..0000000
--- a/res/drawable-mdpi/corpus_indicator_bg_default.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/corpus_indicator_bg_focused.png b/res/drawable-mdpi/corpus_indicator_bg_focused.png
index acb4c3d..0f82471 100644
--- a/res/drawable-mdpi/corpus_indicator_bg_focused.png
+++ b/res/drawable-mdpi/corpus_indicator_bg_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/corpus_indicator_bg_pressed.png b/res/drawable-mdpi/corpus_indicator_bg_pressed.png
index 0983244..b00a403 100644
--- a/res/drawable-mdpi/corpus_indicator_bg_pressed.png
+++ b/res/drawable-mdpi/corpus_indicator_bg_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/corpus_indicator_blank.9.png b/res/drawable-mdpi/corpus_indicator_blank.9.png
new file mode 100644
index 0000000..27ed46c
--- /dev/null
+++ b/res/drawable-mdpi/corpus_indicator_blank.9.png
Binary files differ
diff --git a/res/drawable-mdpi/voice_search_hint_bg.9.png b/res/drawable-mdpi/voice_search_hint_bg.9.png
deleted file mode 100644
index eb09cbd..0000000
--- a/res/drawable-mdpi/voice_search_hint_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/voice_search_hint_bg_normal.9.png b/res/drawable-mdpi/voice_search_hint_bg_normal.9.png
new file mode 100644
index 0000000..d986f4c
--- /dev/null
+++ b/res/drawable-mdpi/voice_search_hint_bg_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi/voice_search_hint_bg_pressed.9.png b/res/drawable-mdpi/voice_search_hint_bg_pressed.9.png
new file mode 100644
index 0000000..fd65733
--- /dev/null
+++ b/res/drawable-mdpi/voice_search_hint_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/voice_search_hint_bg_selected.9.png b/res/drawable-mdpi/voice_search_hint_bg_selected.9.png
new file mode 100644
index 0000000..f52007e
--- /dev/null
+++ b/res/drawable-mdpi/voice_search_hint_bg_selected.9.png
Binary files differ
diff --git a/res/drawable/corpus_indicator_bg.xml b/res/drawable/corpus_indicator_bg.xml
index 04861bf..995d2d2 100644
--- a/res/drawable/corpus_indicator_bg.xml
+++ b/res/drawable/corpus_indicator_bg.xml
@@ -17,15 +17,15 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/corpus_indicator_bg_default" />
+        android:drawable="@drawable/corpus_indicator_arrow" />
 
     <item android:state_pressed="true"
-        android:drawable="@drawable/corpus_indicator_bg_pressed" />
+        android:drawable="@drawable/corpus_indicator_bg_pressed_arrow" />
 
     <item android:state_focused="true"
-        android:drawable="@drawable/corpus_indicator_bg_focused" />
+        android:drawable="@drawable/corpus_indicator_bg_focused_arrow" />
 
     <item android:state_enabled="true"
-        android:drawable="@drawable/corpus_indicator_bg_default" />
+        android:drawable="@drawable/corpus_indicator_arrow" />
 
 </selector>
diff --git a/res/drawable/corpus_indicator_bg_focused_arrow.xml b/res/drawable/corpus_indicator_bg_focused_arrow.xml
new file mode 100644
index 0000000..28ed7e1
--- /dev/null
+++ b/res/drawable/corpus_indicator_bg_focused_arrow.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/corpus_indicator_bg_focused" />
+
+    <item android:drawable="@drawable/corpus_indicator_arrow" />
+
+</layer-list>
diff --git a/res/drawable/corpus_indicator_bg_noarrow.xml b/res/drawable/corpus_indicator_bg_noarrow.xml
new file mode 100644
index 0000000..279b7f6
--- /dev/null
+++ b/res/drawable/corpus_indicator_bg_noarrow.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- We use a blank 9-patch here to work around a bug in the android framework. A subtle problem
+    in LayerDrawable means that if it is composed of simple drawable objects, it will reset the
+    padding of it's host view when set as the background. Using a 9-patch means that we can 'hard-
+    code' the padding we want into the 9 patch, so when it resets its host views padding it doesn't
+    actually change it. (drawable/corpus_indicator_bg uses layer drawables to composite an arrow
+    on top of these basic background). See bug 2826716. -->
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/corpus_indicator_blank" />
+
+    <item android:state_pressed="true"
+        android:drawable="@drawable/corpus_indicator_bg_pressed" />
+
+    <item android:state_focused="true"
+        android:drawable="@drawable/corpus_indicator_bg_focused" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/corpus_indicator_blank" />
+
+</selector>
diff --git a/res/drawable/corpus_indicator_bg_pressed_arrow.xml b/res/drawable/corpus_indicator_bg_pressed_arrow.xml
new file mode 100644
index 0000000..434aa5e
--- /dev/null
+++ b/res/drawable/corpus_indicator_bg_pressed_arrow.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/corpus_indicator_bg_pressed" />
+
+    <item android:drawable="@drawable/corpus_indicator_arrow" />
+
+</layer-list>
+
diff --git a/res/drawable/voice_search_hint_bg.xml b/res/drawable/voice_search_hint_bg.xml
new file mode 100644
index 0000000..15bf6d2
--- /dev/null
+++ b/res/drawable/voice_search_hint_bg.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/voice_search_hint_bg_normal" />
+
+    <item android:state_pressed="true"
+        android:drawable="@drawable/voice_search_hint_bg_pressed" />
+
+    <item android:state_focused="true"
+        android:drawable="@drawable/voice_search_hint_bg_selected" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/voice_search_hint_bg_normal" />
+
+</selector>
diff --git a/res/layout/search_widget.xml b/res/layout/search_widget.xml
index bc0a8db..2324b44 100644
--- a/res/layout/search_widget.xml
+++ b/res/layout/search_widget.xml
@@ -56,6 +56,17 @@
             android:textColorHint="@color/search_hint"
         />
 
+        <include
+            android:id="@+id/voice_search_hint"
+            layout="@layout/voice_search_hint"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginTop="6dip"
+            android:layout_marginBottom="6dip"
+            android:focusable="true"
+        />
+
         <ImageButton
             android:id="@+id/search_widget_voice_btn"
             android:layout_width="wrap_content"
@@ -67,13 +78,4 @@
 
     </LinearLayout>
 
-    <include
-        android:id="@+id/voice_search_hint"
-        layout="@layout/voice_search_hint"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentRight="true"
-    />
-
 </RelativeLayout>
diff --git a/res/layout/voice_search_hint.xml b/res/layout/voice_search_hint.xml
index a83d7e0..f62f7f7 100644
--- a/res/layout/voice_search_hint.xml
+++ b/res/layout/voice_search_hint.xml
@@ -18,16 +18,19 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:background="@drawable/voice_search_hint_bg"
-        android:orientation="horizontal"
+        android:orientation="vertical"
         android:gravity="center_vertical|left"
         android:visibility="gone"
+        android:paddingLeft="10dip"
+        android:paddingRight="10dip"
+        android:focusable="true"
         >
 
     <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="0.0"
-            android:textColor="#88FFFFFF"
+            android:textColor="#88000000"
             android:textSize="14dip"
             android:gravity="left"
             android:singleLine="true"
@@ -40,21 +43,10 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1.0"
-            android:textColor="@android:color/white"
+            android:textColor="@android:color/black"
             android:textSize="14dip"
             android:gravity="left"
             android:singleLine="true"
             />
 
-    <ImageView
-            android:id="@+id/voice_search_hint_close"
-            android:layout_width="24dip"
-            android:layout_height="24dip"
-            android:layout_weight="0.0"
-            android:paddingLeft="4dip"
-            android:src="@drawable/btn_dialog"
-            android:scaleType="centerInside"
-            android:focusable="true"
-            />
-
 </LinearLayout>
diff --git a/res/layout/widget_suggestion.xml b/res/layout/widget_suggestion.xml
deleted file mode 100644
index 0677702..0000000
--- a/res/layout/widget_suggestion.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/widget_suggestion"
-    android:paddingLeft="0dip"
-    android:paddingRight="0dip"
-    android:layout_width="match_parent"
-    android:layout_height="28dip"
-    android:background="@drawable/suggestion_background"
-    android:focusable="true"
-    android:clickable="true" >
-
-    <ImageView android:id="@+id/icon1"
-        android:layout_width="24dip"
-        android:layout_height="24dip"
-        android:scaleType="centerInside"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentBottom="true" />
-
-   <TextView android:id="@+id/text1"
-        style="?android:attr/dropDownItemStyle"
-        android:textStyle="normal"
-        android:textColor="@android:color/primary_text_light"
-        android:textSize="16sp"
-        android:singleLine="true"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentRight="true"
-        android:layout_toRightOf="@id/icon1"
-        android:layout_alignWithParentIfMissing="true" 
-        />
-
-</RelativeLayout>
diff --git a/src/com/android/quicksearchbox/Config.java b/src/com/android/quicksearchbox/Config.java
index c56c054..1012385 100644
--- a/src/com/android/quicksearchbox/Config.java
+++ b/src/com/android/quicksearchbox/Config.java
@@ -252,6 +252,7 @@
     /**
      * The period of time for which after installing voice search we should consider showing voice
      * search hints.
+     *
      * @return The period in milliseconds.
      */
     public long getVoiceSearchHintActivePeriod() {
@@ -260,6 +261,7 @@
 
     /**
      * The time interval at which we should consider whether or not to show some voice search hints.
+     *
      * @return The period in milliseconds.
      */
     public long getVoiceSearchHintUpdatePeriod() {
@@ -268,6 +270,8 @@
 
     /**
      * The time interval at which, on average, voice search hints are displayed.
+     *
+     * @return The period in milliseconds.
      */
     public long getVoiceSearchHintShowPeriod() {
         return VOICE_SEARCH_HINT_SHOW_PERIOD_MILLIS;
@@ -275,6 +279,7 @@
 
     /**
      * The amount of time for which voice search hints are displayed in one go.
+     *
      * @return The period in milliseconds.
      */
     public long getVoiceSearchHintVisibleTime() {
@@ -283,6 +288,7 @@
 
     /**
      * The period that we change voice search hints at while they're being displayed.
+     *
      * @return The period in milliseconds.
      */
     public long getVoiceSearchHintChangePeriod() {
diff --git a/src/com/android/quicksearchbox/SearchWidgetProvider.java b/src/com/android/quicksearchbox/SearchWidgetProvider.java
index 1321054..358dc27 100644
--- a/src/com/android/quicksearchbox/SearchWidgetProvider.java
+++ b/src/com/android/quicksearchbox/SearchWidgetProvider.java
@@ -77,6 +77,13 @@
             "com.android.quicksearchbox.action.CONSIDER_VOICE_SEARCH_HINT";
 
     /**
+     * Broadcast intent action for displaying voice search hints immediately. This will only have
+     * any effect when {@link #DBG} is true.
+     */
+    private static final String ACTION_SHOW_VOICE_SEARCH_HINT_NOW =
+            "com.android.quicksearchbox.action.SHOW_VOICE_SEARCH_HINT_NOW";
+
+    /**
      * Preference key used for storing the index of the next voice search hint to show.
      */
     private static final String NEXT_VOICE_SEARCH_HINT_INDEX_PREF = "next_voice_search_hint";
@@ -112,6 +119,8 @@
             getHintsFromVoiceSearch(context);
         } else if (ACTION_HIDE_VOICE_SEARCH_HINT.equals(action)) {
             hideVoiceSearchHint(context);
+        } else if (DBG && ACTION_SHOW_VOICE_SEARCH_HINT_NOW.equals(action)) {
+            showVoiceSearchHintNow(context);
         }
     }
 
@@ -179,10 +188,21 @@
         }
         if (changed) {
             getHintsFromVoiceSearch(context);
-            sceduleNextVoiceSearchHint(context, true);
+            scheduleNextVoiceSearchHint(context, true);
         }
     }
 
+    private static void showVoiceSearchHintNow(Context context) {
+        if (DBG) Log.d(TAG, "showVoiceSearchHintNow");
+        SearchWidgetState[] states = getSearchWidgetStates(context, true);
+        for (SearchWidgetState state : states) {
+            state.setShowingHint(true);
+            state.updateShowingHint(context);
+        }
+        getHintsFromVoiceSearch(context);
+        scheduleNextVoiceSearchHint(context, true);
+    }
+
     private void hideVoiceSearchHint(Context context) {
         if (DBG) Log.d(TAG, "hideVoiceSearchHint");
         SearchWidgetState[] states = getSearchWidgetStates(context, true);
@@ -194,7 +214,7 @@
             }
             needHint |= state.isShowingHint();
         }
-        sceduleNextVoiceSearchHint(context, false);
+        scheduleNextVoiceSearchHint(context, false);
     }
 
     private static void voiceSearchHintReceived(Context context, CharSequence hint) {
@@ -210,7 +230,7 @@
             }
         }
         if (!needHint) {
-            sceduleNextVoiceSearchHint(context, false);
+            scheduleNextVoiceSearchHint(context, false);
         }
     }
 
@@ -326,6 +346,11 @@
         }
     }
 
+    private static Intent getVoiceSearchHelpIntent(Context context) {
+        VoiceSearch voiceSearch = QsbApplication.get(context).getVoiceSearch();
+        return voiceSearch.createVoiceSearchHelpIntent();
+    }
+
     private static Uri getCorpusIconUri(Context context, Corpus corpus) {
         if (corpus == null) {
             return getCorpusViewFactory(context).getGlobalSearchIconUri();
@@ -355,13 +380,13 @@
         return spannedHint;
     }
 
-    private static void rescheduleAction(Context context, boolean reshedule, String action, long period) {
+    private static void rescheduleAction(Context context, boolean reschedule, String action, long period) {
         AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         Intent intent = new Intent(action);
         intent.setComponent(myComponentName(context));
         PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
         alarmManager.cancel(pending);
-        if (reshedule) {
+        if (reschedule) {
             if (DBG) Log.d(TAG, "Scheduling action " + action + " after period " + period);
             alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
                     SystemClock.elapsedRealtime() + period, period, pending);
@@ -375,7 +400,7 @@
                 getConfig(context).getVoiceSearchHintUpdatePeriod());
     }
 
-    private static void sceduleNextVoiceSearchHint(Context context, boolean needUpdates) {
+    private static void scheduleNextVoiceSearchHint(Context context, boolean needUpdates) {
         rescheduleAction(context, needUpdates, ACTION_NEXT_VOICE_SEARCH_HINT,
                 getConfig(context).getVoiceSearchHintChangePeriod());
     }
@@ -522,7 +547,7 @@
             return intent;
         }
 
-        private void sheduleHintHiding(Context context) {
+        private void scheduleHintHiding(Context context) {
             Intent hideIntent = createIntent(context, ACTION_HIDE_VOICE_SEARCH_HINT);
 
             AlarmManager alarmManager =
@@ -539,14 +564,14 @@
 
         }
 
-        private void updateShowingHint(Context context) {
+        public void updateShowingHint(Context context) {
             SearchWidgetConfigActivity.setWidgetShowingHint(context, mAppWidgetId, mShowHint);
         }
 
         public boolean considerShowingHint(Context context) {
             if (!mVoiceSearchHintsEnabled || mShowHint) return false;
             if (!chooseToShowHint(context)) return false;
-            sheduleHintHiding(context);
+            scheduleHintHiding(context);
             mShowHint = true;
             updateShowingHint(context);
             return true;
@@ -565,15 +590,10 @@
             if (QsbApplication.isFroyoOrLater()) {
                 views.setImageViewUri(R.id.corpus_indicator, mCorpusIconUri);
             }
-            setOnClickActivityIntent(context, views, R.id.corpus_indicator,
-                    mCorpusIndicatorIntent);
             // Query TextView
             views.setCharSequence(R.id.search_widget_text, "setHint", mQueryTextViewHint);
-            // setBackgroundResource did not have @RemotableViewMethod before Froyo
-            if (QsbApplication.isFroyoOrLater()) {
-                views.setInt(R.id.search_widget_text, "setBackgroundResource",
-                        mQueryTextViewBackgroundResource);
-            }
+            setBackgroundResource(views, R.id.search_widget_text, mQueryTextViewBackgroundResource);
+
             setOnClickActivityIntent(context, views, R.id.search_widget_text,
                     mQueryTextViewIntent);
             // Voice Search button
@@ -589,20 +609,35 @@
             if (mShowHint && !TextUtils.isEmpty(mVoiceSearchHint)) {
                 views.setTextViewText(R.id.voice_search_hint_text, mVoiceSearchHint);
 
-                Intent closeHintIntent = createIntent(context, ACTION_HIDE_VOICE_SEARCH_HINT);
-                setOnClickBroadcastIntent(context, views, R.id.voice_search_hint_close,
-                        closeHintIntent);
-
-                setOnClickActivityIntent(context, views, R.id.voice_search_hint_text,
-                        mVoiceSearchIntent);
+                Intent voiceSearchHelp = getVoiceSearchHelpIntent(context);
+                if (voiceSearchHelp == null) voiceSearchHelp = mVoiceSearchIntent;
+                setOnClickActivityIntent(context, views, R.id.voice_search_hint,
+                        voiceSearchHelp);
 
                 views.setViewVisibility(R.id.voice_search_hint, View.VISIBLE);
+                views.setViewVisibility(R.id.search_widget_text, View.GONE);
+
+                setBackgroundResource(views, R.id.corpus_indicator,
+                        R.drawable.corpus_indicator_bg_noarrow);
+                setOnClickBroadcastIntent(context, views, R.id.corpus_indicator,
+                        createIntent(context, ACTION_HIDE_VOICE_SEARCH_HINT));
             } else {
                 views.setViewVisibility(R.id.voice_search_hint, View.GONE);
+                views.setViewVisibility(R.id.search_widget_text, View.VISIBLE);
+                setBackgroundResource(views, R.id.corpus_indicator, R.drawable.corpus_indicator_bg);
+                setOnClickActivityIntent(context, views, R.id.corpus_indicator,
+                        mCorpusIndicatorIntent);
             }
             appWidgetMgr.updateAppWidget(mAppWidgetId, views);
         }
 
+        private void setBackgroundResource(RemoteViews views, int viewId, int bgResource) {
+            // setBackgroundResource did not have @RemotableViewMethod before Froyo
+            if (QsbApplication.isFroyoOrLater()) {
+                views.setInt(viewId, "setBackgroundResource", bgResource);
+            }
+        }
+
         private void setOnClickBroadcastIntent(Context context, RemoteViews views, int viewId,
                 Intent intent) {
             PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
diff --git a/src/com/android/quicksearchbox/VoiceSearch.java b/src/com/android/quicksearchbox/VoiceSearch.java
index e826784..fbc6dac 100644
--- a/src/com/android/quicksearchbox/VoiceSearch.java
+++ b/src/com/android/quicksearchbox/VoiceSearch.java
@@ -20,8 +20,8 @@
 import android.content.Intent;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.speech.RecognizerIntent;
 import android.util.Log;
@@ -79,7 +79,16 @@
     }
 
     /**
+     * Create an intent to launch the voice search help screen, if any exists.
+     * @return The intent, or null.
+     */
+    public Intent createVoiceSearchHelpIntent() {
+        return null;
+    }
+
+    /**
      * Gets the {@code versionCode} of the currently installed voice search package.
+     *
      * @return The {@code versionCode} of voiceSearch, or 0 if none is installed.
      */
     public int getVersion() {