Fix 6299832: Add search target swipe action to navigation bar on phones

This adds a feature to swipe upward on the navigation bar to invoke
voice search on phones.

Change-Id: I462076fd43b1c66c5bf624f00b297c6d3414a19a
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index bc310b0..d62f513 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -429,6 +429,12 @@
         public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
 
         /**
+         * Window type: Navigation bar panel (when navigation bar is distinct from status bar)
+         * @hide
+         */
+        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index f2b6e45..624dea8 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -27,7 +27,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.os.Vibrator;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -142,6 +141,7 @@
     private int mTargetResourceId;
     private int mTargetDescriptionsResourceId;
     private int mDirectionDescriptionsResourceId;
+    private boolean mAlwaysTrackFinger;
 
     public MultiWaveView(Context context) {
         this(context, null);
@@ -168,6 +168,7 @@
         mTapRadius = mHandleDrawable.getWidth()/2;
         mOuterRing = new TargetDrawable(res,
                 a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
+        mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false);
 
         // Read chevron animation drawables
         final int chevrons[] = { R.styleable.MultiWaveView_leftChevronDrawable,
@@ -634,7 +635,6 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getAction();
-
         boolean handled = false;
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -805,7 +805,7 @@
         final float y = event.getY();
         final float dx = x - mWaveCenterX;
         final float dy = y - mWaveCenterY;
-        if (dist2(dx,dy) <= getScaledTapRadiusSquared()) {
+        if (mAlwaysTrackFinger || dist2(dx,dy) <= getScaledTapRadiusSquared()) {
             if (DEBUG) Log.v(TAG, "** Handle HIT");
             switchToState(STATE_FIRST_TOUCH, x, y);
             moveHandleTo(x, y, false);
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..2c4847c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..d98557d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..656f3ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..32a68e0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..3f96d03
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..2f7efcf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..d643f83
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..51863f4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..9a9bf68
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
deleted file mode 100644
index c625a36..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
deleted file mode 100644
index c625a36..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_search.xml b/core/res/res/drawable/ic_lockscreen_search.xml
index b103922..2c0091a 100644
--- a/core/res/res/drawable/ic_lockscreen_search.xml
+++ b/core/res/res/drawable/ic_lockscreen_search.xml
@@ -19,12 +19,12 @@
         android:state_enabled="true"
         android:state_active="false"
         android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_search_normal" />
+        android:drawable="@drawable/ic_lockscreen_google_normal" />
 
     <item
         android:state_enabled="true"
         android:state_active="true"
         android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_search_activated" />
+        android:drawable="@drawable/ic_lockscreen_google_activated" />
 
 </selector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0ac381d..9fa666e 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5383,6 +5383,9 @@
 
         <!-- Used to shift center of pattern horizontally. -->
         <attr name="horizontalOffset" format="dimension" />
+
+        <!-- Used when the handle shouldn't wait to be hit before following the finger -->
+        <attr name="alwaysTrackFinger" format="boolean" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png b/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png
new file mode 100644
index 0000000..d595ed2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/navbar_search_handle.xml b/packages/SystemUI/res/drawable/navbar_search_handle.xml
new file mode 100644
index 0000000..e40fa2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_handle.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@*android:drawable/ic_lockscreen_handle_pressed" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@*android:drawable/ic_lockscreen_handle_pressed" />
+
+</selector>
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
new file mode 100644
index 0000000..37b6c1c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <size android:height="@dimen/navbar_search_outerring_diameter"
+        android:width="@dimen/navbar_search_outerring_diameter" />
+    <solid android:color="#00000000" />
+    <stroke android:color="#1affffff" android:width="2dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
new file mode 100644
index 0000000..2adee33
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<com.android.systemui.SearchPanelView
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/search_panel_container"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:paddingBottom="0dip">
+
+    <RelativeLayout
+        android:id="@+id/search_bg_protect"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="0dip">
+
+        <RelativeLayout
+            android:id="@+id/search_panel_container"
+            android:layout_width="230dip"
+            android:layout_height="match_parent"
+            android:layout_alignParentRight="true">
+
+            <com.android.internal.widget.multiwaveview.MultiWaveView
+                android:id="@+id/multi_wave_view"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:background="@drawable/navbar_search_bg_scrim"
+
+                prvandroid:targetDrawables="@array/navbar_search_targets"
+                prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
+                prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
+                prvandroid:handleDrawable="@drawable/navbar_search_handle"
+                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_target_placement_radius"
+                prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
+                prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
+                prvandroid:verticalOffset="0dip"
+                prvandroid:horizontalOffset="60dip"
+                prvandroid:feedbackCount="0"
+                prvandroid:vibrationDuration="0"
+                prvandroid:alwaysTrackFinger="true"/>
+
+        </RelativeLayout>
+
+    </RelativeLayout>
+
+</com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
new file mode 100644
index 0000000..463fa04
--- /dev/null
+++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<com.android.systemui.SearchPanelView
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/search_panel_container"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:paddingBottom="0dip">
+
+    <RelativeLayout
+        android:id="@+id/search_bg_protect"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="0dip">
+
+        <RelativeLayout
+            android:id="@+id/search_panel_container"
+            android:layout_width="match_parent"
+            android:layout_height="230dip"
+            android:layout_alignParentBottom="true">
+
+            <com.android.internal.widget.multiwaveview.MultiWaveView
+                android:id="@+id/multi_wave_view"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:background="@drawable/navbar_search_bg_scrim"
+
+                prvandroid:targetDrawables="@array/navbar_search_targets"
+                prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
+                prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
+                prvandroid:handleDrawable="@drawable/navbar_search_handle"
+                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_target_placement_radius"
+                prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
+                prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
+                prvandroid:horizontalOffset="0dip"
+                prvandroid:verticalOffset="60dip"
+                prvandroid:feedbackCount="0"
+                prvandroid:vibrationDuration="0"
+                prvandroid:alwaysTrackFinger="true"/>
+
+        </RelativeLayout>
+
+    </RelativeLayout>
+
+</com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/values-land/arrays.xml b/packages/SystemUI/res/values-land/arrays.xml
new file mode 100644
index 0000000..53f374d
--- /dev/null
+++ b/packages/SystemUI/res/values-land/arrays.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <array name="navbar_search_targets">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:drawable/ic_lockscreen_search</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_target_descriptions">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:string/description_target_search</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_direction_descriptions">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:string/description_direction_left</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/packages/SystemUI/res/values-port/arrays.xml b/packages/SystemUI/res/values-port/arrays.xml
new file mode 100644
index 0000000..f8b1620
--- /dev/null
+++ b/packages/SystemUI/res/values-port/arrays.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    
+    <array name="navbar_search_targets">
+        <item>@null</item>
+        <item>@*android:drawable/ic_lockscreen_search</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_target_descriptions">
+        <item>@null</item>
+        <item>@*android:string/description_target_search</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_direction_descriptions">
+        <item>@null</item>
+        <item>@*android:string/description_direction_up</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b8e8fe4..531f154 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -105,4 +105,17 @@
 
     <!-- The width of the view containing the menu status bar icon -->
     <dimen name="navigation_menu_key_width">40dip</dimen>
+
+    <!-- Default target placement radius for navigation bar search target -->
+    <dimen name="navbar_search_target_placement_radius">150dip</dimen>
+
+    <!-- Default distance beyond which snaps to the target radius -->
+    <dimen name="navbar_search_snap_margin">20dip</dimen>
+
+    <!-- Default distance from each snap target considers a "hit" -->
+    <dimen name="navbar_search_hit_radius">60dip</dimen>
+
+    <!-- Diameter of outer shape drawable shown in navbar search-->
+    <dimen name="navbar_search_outerring_diameter">300dip</dimen>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
new file mode 100644
index 0000000..369a093
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012 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.systemui;
+
+import android.animation.Animator;
+import android.animation.LayoutTransition;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.speech.RecognizerIntent;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.internal.widget.multiwaveview.MultiWaveView;
+import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
+import com.android.systemui.R;
+import com.android.systemui.recent.StatusBarTouchProxy;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+import com.android.systemui.statusbar.tablet.TabletStatusBar;
+
+public class SearchPanelView extends FrameLayout implements
+        StatusBarPanel, Animator.AnimatorListener {
+    static final String TAG = "SearchPanelView";
+    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
+    private Context mContext;
+    private BaseStatusBar mBar;
+    private StatusBarTouchProxy mStatusBarTouchProxy;
+
+    private boolean mShowing;
+    private View mSearchTargetsContainer;
+    private MultiWaveView mMultiWaveView;
+
+
+    public SearchPanelView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mContext = context;
+    }
+
+    final MultiWaveView.OnTriggerListener mMultiWaveViewListener
+            = new MultiWaveView.OnTriggerListener() {
+
+        public void onGrabbed(View v, int handle) {
+        }
+
+        public void onReleased(View v, int handle) {
+        }
+
+        public void onGrabbedStateChange(View v, int handle) {
+            if (OnTriggerListener.NO_HANDLE == handle) {
+                mBar.hideSearchPanel();
+            }
+        }
+
+        public void onTrigger(View v, int target) {
+            final int resId = mMultiWaveView.getResourceIdForTarget(target);
+            switch (resId) {
+                case com.android.internal.R.drawable.ic_lockscreen_search:
+                    Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+                    intent.setFlags(
+                            Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    try {
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, "Application not found for action " + intent.getAction());
+                    }
+                    mBar.hideSearchPanel();
+                break;
+            }
+        }
+    };
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mSearchTargetsContainer = (ViewGroup) findViewById(R.id.search_panel_container);
+        mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
+        // TODO: fetch views
+        mMultiWaveView = (MultiWaveView) findViewById(R.id.multi_wave_view);
+        mMultiWaveView.setOnTriggerListener(mMultiWaveViewListener);
+    }
+
+    private boolean pointInside(int x, int y, View v) {
+        final int l = v.getLeft();
+        final int r = v.getRight();
+        final int t = v.getTop();
+        final int b = v.getBottom();
+        return x >= l && x < r && y >= t && y < b;
+    }
+
+    public boolean isInContentArea(int x, int y) {
+        if (pointInside(x, y, mSearchTargetsContainer)) {
+            return true;
+        } else if (mStatusBarTouchProxy != null &&
+                pointInside(x, y, mStatusBarTouchProxy)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void show(boolean show, boolean animate) {
+        if (animate) {
+            if (mShowing != show) {
+                mShowing = show;
+                // TODO: start animating ring
+            }
+        } else {
+            mShowing = show;
+            onAnimationEnd(null);
+        }
+        setVisibility(show ? View.VISIBLE : View.GONE);
+        if (show) {
+            setFocusable(true);
+            setFocusableInTouchMode(true);
+            requestFocus();
+        }
+    }
+
+    public void hide(boolean animate) {
+        if (!animate) {
+            setVisibility(View.GONE);
+        }
+        if (mBar != null) {
+            // This will indirectly cause show(false, ...) to get called
+            mBar.animateCollapse();
+        }
+    }
+
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    public void onAnimationEnd(Animator animation) {
+        if (mShowing) {
+            final LayoutTransition transitioner = new LayoutTransition();
+            ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(transitioner);
+            createCustomAnimations(transitioner);
+        } else {
+            ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(null);
+        }
+    }
+
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    public void onAnimationStart(Animator animation) {
+    }
+
+    /**
+     * We need to be aligned at the bottom.  LinearLayout can't do this, so instead,
+     * let LinearLayout do all the hard work, and then shift everything down to the bottom.
+     */
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        // setPanelHeight(mSearchTargetsContainer.getHeight());
+    }
+
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
+    /**
+     * Whether the panel is showing, or, if it's animating, whether it will be
+     * when the animation is done.
+     */
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    public void setBar(BaseStatusBar bar) {
+        mBar = bar;
+    }
+
+    public void setStatusBarView(final View statusBarView) {
+        if (mStatusBarTouchProxy != null) {
+            mStatusBarTouchProxy.setStatusBar(statusBarView);
+//            mMultiWaveView.setOnTouchListener(new OnTouchListener() {
+//                public boolean onTouch(View v, MotionEvent event) {
+//                    return statusBarView.onTouchEvent(event);
+//                }
+//            });
+        }
+    }
+
+    private void createCustomAnimations(LayoutTransition transitioner) {
+        transitioner.setDuration(200);
+        transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
+        transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 19306a9..4dd96fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -55,6 +55,7 @@
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.internal.widget.SizeAdaptiveLayout;
+import com.android.systemui.SearchPanelView;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.recent.RecentTasksLoader;
@@ -73,6 +74,8 @@
     protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
     protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
+    protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
+    protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
 
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
@@ -81,6 +84,9 @@
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
 
+    // Search panel
+    protected SearchPanelView mSearchPanelView;
+
     // Recent apps
     protected RecentsPanelView mRecentsPanel;
     protected RecentTasksLoader mRecentTasksLoader;
@@ -278,12 +284,29 @@
     }
 
     @Override
+    public void showSearchPanel() {
+        int msg = MSG_OPEN_SEARCH_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        int msg = MSG_CLOSE_SEARCH_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
     public void onRecentsPanelVisibilityChanged(boolean visible) {
     }
 
     protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
             LayoutParams layoutParams);
 
+    protected abstract WindowManager.LayoutParams getSearchLayoutParams(
+            LayoutParams layoutParams);
+
     protected void updateRecentsPanel(int recentsResId) {
         // Recents Panel
         boolean visible = false;
@@ -319,6 +342,31 @@
 
     }
 
+    protected void updateSearchPanel() {
+        // Search Panel
+        boolean visible = false;
+        if (mSearchPanelView != null) {
+            visible = mSearchPanelView.isShowing();
+            WindowManagerImpl.getDefault().removeView(mSearchPanelView);
+        }
+
+        // Provide SearchPanel with a temporary parent to allow layout params to work.
+        LinearLayout tmpRoot = new LinearLayout(mContext);
+        mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
+                 R.layout.status_bar_search_panel, tmpRoot, false);
+        mSearchPanelView.setOnTouchListener(
+                 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
+        mSearchPanelView.setVisibility(View.GONE);
+
+        WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
+
+        WindowManagerImpl.getDefault().addView(mSearchPanelView, lp);
+        mSearchPanelView.setBar(this);
+        if (visible) {
+            mSearchPanelView.show(true, false);
+        }
+    }
+
     protected H createHandler() {
          return new H();
     }
@@ -346,6 +394,18 @@
                   if (DEBUG) Slog.d(TAG, "cancel preloading recents");
                   mRecentsPanel.clearRecentTasksList();
                   break;
+             case MSG_OPEN_SEARCH_PANEL:
+                 if (DEBUG) Slog.d(TAG, "opening search panel");
+                 if (mSearchPanelView != null) {
+                     mSearchPanelView.show(true, true);
+                 }
+                 break;
+             case MSG_CLOSE_SEARCH_PANEL:
+                 if (DEBUG) Slog.d(TAG, "closing search panel");
+                 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
+                     mSearchPanelView.show(false, true);
+                 }
+                 break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f88a3cc9..4209354 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -59,7 +59,7 @@
     private static final int MSG_TOP_APP_WINDOW_CHANGED = 8 << MSG_SHIFT;
     private static final int MSG_SHOW_IME_BUTTON        = 9 << MSG_SHIFT;
     private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
-    
+
     private static final int MSG_TOGGLE_RECENT_APPS       = 11 << MSG_SHIFT;
     private static final int MSG_PRELOAD_RECENT_APPS      = 12 << MSG_SHIFT;
     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS       = 13 << MSG_SHIFT;
@@ -95,6 +95,8 @@
         public void setHardKeyboardStatus(boolean available, boolean enabled);
         public void toggleRecentApps();
         public void preloadRecentApps();
+        public void showSearchPanel();
+        public void hideSearchPanel();
         public void cancelPreloadRecentApps();
         public void setNavigationIconHints(int hints);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
new file mode 100644
index 0000000..f725724
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.VelocityTracker;
+import android.view.View;
+
+public class DelegateViewHelper {
+    private static final int VELOCITY_THRESHOLD = 1000;
+    private VelocityTracker mVelocityTracker;
+    private View mDelegateView;
+    private View mSourceView;
+    private BaseStatusBar mBar;
+    private int[] mTempPoint = new int[2];
+    private int mOrientation;
+
+    public DelegateViewHelper(View sourceView) {
+        mSourceView = sourceView;
+    }
+
+    public void setDelegateView(View view) {
+        mDelegateView = view;
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mBar = phoneStatusBar;
+    }
+
+    public void setOrientation(int orientation) {
+        mOrientation = orientation;
+    }
+
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mVelocityTracker = VelocityTracker.obtain();
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
+                break;
+        }
+        if (mVelocityTracker != null) {
+            if (mDelegateView != null && mDelegateView.getVisibility() != View.VISIBLE) {
+                mVelocityTracker.addMovement(event);
+                mVelocityTracker.computeCurrentVelocity(1000);
+                final boolean isVertical = (mOrientation == Surface.ROTATION_90
+                        || mOrientation == Surface.ROTATION_270);
+                float velocity = isVertical ? - mVelocityTracker.getXVelocity()
+                        : - mVelocityTracker.getYVelocity();
+                if (velocity > VELOCITY_THRESHOLD) {
+                    if (mDelegateView != null && mDelegateView.getVisibility() != View.VISIBLE) {
+                        mBar.showSearchPanel();
+                    }
+                }
+            }
+        }
+        if (mDelegateView != null) {
+            mSourceView.getLocationOnScreen(mTempPoint);
+            float deltaX = mTempPoint[0];
+            float deltaY = mTempPoint[1];
+
+            mDelegateView.getLocationOnScreen(mTempPoint);
+            deltaX -= mTempPoint[0];
+            deltaY -= mTempPoint[1];
+
+            event.offsetLocation(deltaX, deltaY);
+            mDelegateView.dispatchTouchEvent(event);
+            event.offsetLocation(-deltaX, -deltaY);
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 11e067f..73c5d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -31,10 +31,12 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.Display;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Surface;
 import android.view.WindowManager;
+import android.view.WindowManagerImpl;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -43,8 +45,9 @@
 import java.lang.StringBuilder;
 
 import com.android.internal.statusbar.IStatusBarService;
-
 import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.DelegateViewHelper;
 
 public class NavigationBarView extends LinearLayout {
     final static boolean DEBUG = false;
@@ -68,6 +71,8 @@
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
+    private DelegateViewHelper mDelegateHelper;
+
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
     final static int MSG_CHECK_INVALID_LAYOUT = 8686;
@@ -95,6 +100,19 @@
         }
     }
 
+    public void setDelegateView(View view) {
+        mDelegateHelper.setDelegateView(view);
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mDelegateHelper.setBar(phoneStatusBar);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mDelegateHelper.onInterceptTouchEvent(event);
+    }
+
     private H mHandler = new H();
 
     public View getRecentsButton() {
@@ -127,6 +145,7 @@
         mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
         mVertical = false;
         mShowMenu = false;
+        mDelegateHelper = new DelegateViewHelper(this);
     }
 
     View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
@@ -411,4 +430,5 @@
                 );
         pw.println("    }");
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 61500e9..80ee64f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -258,7 +258,7 @@
     // ================================================================================
     // Constructing the view
     // ================================================================================
-    protected View makeStatusBarView() {
+    protected PhoneStatusBarView makeStatusBarView() {
         final Context context = mContext;
 
         Resources res = context.getResources();
@@ -294,6 +294,7 @@
                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
 
                 mNavigationBarView.setDisabledFlags(mDisabled);
+                mNavigationBarView.setBar(this);
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
@@ -389,6 +390,32 @@
         return lp;
     }
 
+    @Override
+    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
+        boolean opaque = false;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+        if (ActivityManager.isHighEndGfx(mDisplay)) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        } else {
+            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            lp.dimAmount = 0.7f;
+        }
+        lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+        lp.setTitle("SearchPanel");
+        // TODO: Define custom animation for Search panel
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
     protected void updateRecentsPanel() {
         super.updateRecentsPanel(R.layout.status_bar_recent_panel);
         // Make .03 alpha the minimum so you always see the item a bit-- slightly below
@@ -397,6 +424,33 @@
         mRecentsPanel.setMinSwipeAlpha(0.03f);
     }
 
+    @Override
+    protected void updateSearchPanel() {
+        super.updateSearchPanel();
+        mSearchPanelView.setStatusBarView(mStatusBarView);
+        mNavigationBarView.setDelegateView(mSearchPanelView);
+    }
+
+    @Override
+    public void showSearchPanel() {
+        super.showSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        super.hideSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+    }
+
     protected int getStatusBarGravity() {
         return Gravity.TOP | Gravity.FILL_HORIZONTAL;
     }
@@ -412,12 +466,30 @@
         }
     };
     private StatusBarNotification mCurrentlyIntrudingNotification;
+    View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
+        public boolean onTouch(View v, MotionEvent event) {
+            switch(event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    Slog.d(TAG, "showing search panel");
+                    showSearchPanel();
+                break;
+
+                case MotionEvent.ACTION_UP:
+                    Slog.d(TAG, "hiding search panel");
+                    hideSearchPanel();
+                break;
+            }
+            return false;
+        }
+    };
 
     private void prepareNavigationBarView() {
         mNavigationBarView.reorient();
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+        updateSearchPanel();
+//        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
     }
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
@@ -528,7 +600,7 @@
             Slog.d(TAG, "Presenting high-priority notification");
             // special new transient ticker mode
             // 1. Populate mIntruderAlertView
-            
+
             if (notification.notification.intruderView == null) {
                 Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
                 return;
@@ -544,7 +616,7 @@
             mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
 
             mCurrentlyIntrudingNotification = notification;
-            
+
             // 2. Animate mIntruderAlertView in
             mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
 
@@ -698,7 +770,7 @@
 
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-            
+
             if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
                 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
             }
@@ -1672,7 +1744,7 @@
         addStatusBarWindow();
         addExpandedWindow();
     }
-    
+
     private void addStatusBarWindow() {
         // Put up the view
         final int height = getStatusBarHeight();
@@ -1697,9 +1769,10 @@
         lp.gravity = getStatusBarGravity();
         lp.setTitle("StatusBar");
         lp.packageName = mContext.getPackageName();
-        WindowManagerImpl.getDefault().addView(makeStatusBarView(), lp);
+        mStatusBarView = makeStatusBarView();
+        WindowManagerImpl.getDefault().addView(mStatusBarView, lp);
     }
-    
+
     void addExpandedWindow() {
         WindowManager.LayoutParams lp;
         int pixelFormat;
@@ -1780,11 +1853,11 @@
                 panelh = disph;
             }
         }
-        
+
         // catch orientation changes and other peculiar cases
         if (panelh > disph || (panelh < disph && !mTracking && !mAnimating))
             panelh = disph;
-        
+
         mTrackingPosition = panelh;
         // XXX: this is all very WIP
         //mNotificationPanel.setY(panelh);
@@ -1796,9 +1869,9 @@
         final float frac = (float)panelh / disph;
         final int color = ((int)(0xB0 * frac * frac)) << 24;
         mExpandedWindowView.setBackgroundColor(color);
-        
+
 //        Slog.d(TAG, String.format("updateExpanded: pos=%d frac=%.2f col=0x%08x", pos, frac, color));
-        
+
 //        if (mExpandedParams != null) {
 //            if (mCloseView.getWindowVisibility() == View.VISIBLE) {
 //                mCloseView.getLocationInWindow(mPositionTmp);
@@ -2060,7 +2133,7 @@
             // oh well
         }
     }
-    
+
     /**
      * Reload some of our resources when the configuration changes.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 7b3b745..3bdefcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -18,6 +18,7 @@
 
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -174,7 +175,7 @@
     KeyEvent mSpaceBarKeyEvent = null;
 
     View mCompatibilityHelpDialog = null;
-    
+
     // for disabling the status bar
     int mDisabled = 0;
 
@@ -192,7 +193,7 @@
         addStatusBarWindow();
         addPanelWindows();
     }
-    
+
     private void addStatusBarWindow() {
         final View sb = makeStatusBarView();
 
@@ -328,6 +329,10 @@
         mRecentTasksLoader = new RecentTasksLoader(context);
         updateRecentsPanel();
 
+        // Search Panel
+        mStatusBarView.setBar(this);
+        updateSearchPanel();
+
         // Input methods Panel
         mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
                 R.layout.system_bar_input_methods_panel, null);
@@ -350,7 +355,7 @@
         lp.windowAnimations = R.style.Animation_RecentPanel;
 
         WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp);
-        
+
         // Compatibility mode selector panel
         mCompatModePanel = (CompatModePanel) View.inflate(context,
                 R.layout.system_bar_compat_mode_panel, null);
@@ -373,7 +378,7 @@
         lp.windowAnimations = android.R.style.Animation_Dialog;
 
         WindowManagerImpl.getDefault().addView(mCompatModePanel, lp);
-        
+
         mRecentButton.setOnTouchListener(mRecentsPanel);
 
         mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
@@ -646,11 +651,64 @@
         return lp;
     }
 
+    @Override
+    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
+        boolean opaque = false;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+        if (ActivityManager.isHighEndGfx(mDisplay)) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        } else {
+            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            lp.dimAmount = 0.7f;
+        }
+        lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+        lp.setTitle("SearchPanel");
+        // TODO: Define custom animation for Search panel
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
     protected void updateRecentsPanel() {
         super.updateRecentsPanel(R.layout.system_bar_recent_panel);
         mRecentsPanel.setStatusBarView(mStatusBarView);
     }
 
+    @Override
+    protected void updateSearchPanel() {
+        super.updateSearchPanel();
+        mSearchPanelView.setStatusBarView(mStatusBarView);
+        mStatusBarView.setDelegateView(mSearchPanelView);
+    }
+
+    @Override
+    public void showSearchPanel() {
+        super.showSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        super.hideSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
+        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+    }
+
     public int getStatusBarHeight() {
         return mStatusBarView != null ? mStatusBarView.getHeight()
                 : mContext.getResources().getDimensionPixelSize(
@@ -1191,7 +1249,7 @@
         if (mCompatibilityHelpDialog != null) {
             return;
         }
-        
+
         mCompatibilityHelpDialog = View.inflate(mContext, R.layout.compat_mode_help, null);
         View button = mCompatibilityHelpDialog.findViewById(R.id.button);
 
@@ -1227,7 +1285,7 @@
             mCompatibilityHelpDialog = null;
         }
     }
-    
+
     public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
         mInputMethodSwitchButton.setImeWindowStatus(token,
                 (vis & InputMethodService.IME_ACTIVE) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 877a40e..a6fc396 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.tablet;
 
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.DelegateViewHelper;
+
 import android.content.Context;
 import android.os.Handler;
 import android.util.AttributeSet;
@@ -31,13 +34,24 @@
     private final View[] mIgnoreChildren = new View[MAX_PANELS];
     private final View[] mPanels = new View[MAX_PANELS];
     private final int[] mPos = new int[2];
+    private DelegateViewHelper mDelegateHelper;
 
     public TabletStatusBarView(Context context) {
         super(context);
+        mDelegateHelper = new DelegateViewHelper(this);
     }
 
     public TabletStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mDelegateHelper = new DelegateViewHelper(this);
+    }
+
+    public void setDelegateView(View view) {
+        mDelegateHelper.setDelegateView(view);
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mDelegateHelper.setBar(phoneStatusBar);
     }
 
     @Override
@@ -72,6 +86,9 @@
         if (TabletStatusBar.DEBUG) {
             Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
         }
+        if (mDelegateHelper != null) {
+            return mDelegateHelper.onInterceptTouchEvent(ev);
+        }
         return super.onInterceptTouchEvent(ev);
     }
 
@@ -97,7 +114,7 @@
 
     /**
      * Let the status bar know that if you tap on ignore while panel is showing, don't do anything.
-     * 
+     *
      * Debounces taps on, say, a popup's trigger when the popup is already showing.
      */
     public void setIgnoreChildren(int index, View ignore, View panel) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cc663c2..5086325 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -131,6 +131,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
@@ -216,16 +217,18 @@
     static final int SYSTEM_OVERLAY_LAYER = 18;
     // the navigation bar, if available, shows atop most things
     static final int NAVIGATION_BAR_LAYER = 19;
+    // some panels (e.g. search) need to show on top of the navigation bar
+    static final int NAVIGATION_BAR_PANEL_LAYER = 20;
     // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 20;
+    static final int SYSTEM_ERROR_LAYER = 21;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 21;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 22;
-    static final int BOOT_PROGRESS_LAYER = 23;
+    static final int DRAG_LAYER = 22;
+    static final int SECURE_SYSTEM_OVERLAY_LAYER = 23;
+    static final int BOOT_PROGRESS_LAYER = 24;
     // the (mouse) pointer layer
-    static final int POINTER_LAYER = 24;
-    static final int HIDDEN_NAV_CONSUMER_LAYER = 25;
+    static final int POINTER_LAYER = 25;
+    static final int HIDDEN_NAV_CONSUMER_LAYER = 26;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -1335,6 +1338,8 @@
             return POINTER_LAYER;
         case TYPE_NAVIGATION_BAR:
             return NAVIGATION_BAR_LAYER;
+        case TYPE_NAVIGATION_BAR_PANEL:
+            return NAVIGATION_BAR_PANEL_LAYER;
         case TYPE_BOOT_PROGRESS:
             return BOOT_PROGRESS_LAYER;
         case TYPE_HIDDEN_NAV_CONSUMER:
@@ -1577,6 +1582,11 @@
                 mNavigationBar = win;
                 if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
+            case TYPE_NAVIGATION_BAR_PANEL:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                break;
             case TYPE_STATUS_BAR_PANEL:
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -2480,7 +2490,8 @@
                                     "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
                     }
-                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
+                } else if (attrs.type == TYPE_NAVIGATION_BAR
+                        || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
                     pf.left = df.left = mUnrestrictedScreenLeft;
                     pf.top = df.top = mUnrestrictedScreenTop;