New layout structure for the expanded status bar.

This also includes a new (very WIP) interaction to get to quick
settings, with clumping the cards and a scrollable container with
the cards and the bottom QS part in it.

Change-Id: Ib073bb0174cddcf60347a5e3bb474fb3b6385bcf
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
index 71f7c21..f7035fe 100644
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -25,7 +25,6 @@
         android:id="@+id/content_holder"
         android:layout_height="wrap_content"
         android:layout_width="@dimen/notification_panel_width"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/heads_up_window_bg"
         />
 </com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
index f3c1b90..28d9625 100644
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ b/packages/SystemUI/res/layout/flip_settings.xml
@@ -22,5 +22,4 @@
     android:layout_height="wrap_content"
     android:background="#5f000000"
     android:animateLayoutChanges="true"
-    android:visibility="gone"
     android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 3a58b84..e4954e7 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -22,6 +22,5 @@
         android:layout_height="wrap_content"
         android:layout_width="@dimen/notification_panel_width"
         android:id="@+id/content_holder"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/notification_panel_bg"
         />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 761ad42..3267c36 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,9 +23,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notification_panel"
     android:layout_width="0dp"
-    android:layout_height="wrap_content"
-    android:paddingTop="@dimen/notification_panel_padding_top"
-    android:layout_marginStart="@dimen/notification_panel_margin_left"
+    android:layout_height="match_parent"
     >
 
     <include
@@ -36,15 +34,6 @@
         android:layout_gravity="bottom"
         />
 
-    <include
-        layout="@layout/status_bar_flip_button"
-        android:id="@+id/keyguard_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_gravity="right|top"
-        android:layout_marginTop="@dimen/status_bar_height"
-        android:visibility="gone" />
-
     <com.android.keyguard.CarrierText
         android:id="@+id/keyguard_carrier_text"
         android:layout_width="wrap_content"
@@ -54,11 +43,6 @@
         android:ellipsize="marquee"
         android:textAppearance="?android:attr/textAppearanceMedium" />
 
-    <include layout="@layout/status_bar_expanded_header"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_panel_header_height"
-        />
-
     <include
         layout="@layout/keyguard_status_view"
         android:layout_height="wrap_content"
@@ -74,27 +58,54 @@
         android:visibility="gone"
         />
 
-    <FrameLayout
+    <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
         android:id="@+id/notification_container_parent"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/close_handle_underlap"
-        >
-        <include
-            layout="@layout/flip_settings"
-            android:layout_marginTop="@dimen/notification_panel_header_height"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <com.android.systemui.statusbar.phone.ObservableScrollView
+            android:id="@+id/scroll_view"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
+            android:layout_height="match_parent"
+            android:visibility="invisible"
+            android:scrollbars="none"
+            android:fillViewport="true">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <include
+                    layout="@layout/flip_settings"
+                    android:layout_marginTop="@dimen/status_bar_header_height_expanded"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"/>
+
+                <!-- A view to reserve space for the collapsed stack -->
+                <View
+                    android:layout_height="@dimen/collapsed_stack_height"
+                    android:layout_width="match_parent"/>
+            </LinearLayout>
+        </com.android.systemui.statusbar.phone.ObservableScrollView>
+
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </FrameLayout>
+            android:layout_height="match_parent"
+            android:layout_marginBottom="@dimen/close_handle_underlap"/>
+
+    </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
+
+
+    <include layout="@layout/status_bar_expanded_header"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/status_bar_header_height"
+        />
 
     <include
         layout="@layout/keyguard_bottom_area"
         android:visibility="gone" />
+
 </com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 8975728..460dd4b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,21 +15,30 @@
 ** limitations under the License.
 -->
 
-<LinearLayout
+<!-- Extends RelativeLayout -->
+<com.android.systemui.statusbar.phone.StatusBarHeaderView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_panel_header_height"
-    android:background="@drawable/notification_header_bg"
+    android:layout_height="@dimen/status_bar_header_height"
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:baselineAligned="false"
     >
+
+    <View
+        android:id="@+id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/notification_header_bg"
+        android:clickable="true"
+        />
     <RelativeLayout
         android:id="@+id/datetime"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_gravity="start"
         android:paddingStart="8dp"
         android:paddingEnd="8dp"
         android:background="@drawable/ic_notify_button_bg"
@@ -55,12 +64,6 @@
             />
     </RelativeLayout>
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        />
-
     <TextView
         android:id="@+id/header_debug_info"
         android:visibility="invisible"
@@ -74,18 +77,22 @@
         android:padding="2dp"
         />
 
+    <include layout="@layout/status_bar_flip_button"
+        android:id="@+id/header_flipper"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_alignParentEnd="true"/>
+
     <ImageView android:id="@+id/clear_all_button"
         android:layout_width="50dp"
         android:layout_height="50dp"
+        android:layout_toStartOf="@id/header_flipper"
         android:scaleType="center"
         android:src="@drawable/ic_notify_clear"
         android:background="@drawable/ic_notify_button_bg"
         android:contentDescription="@string/accessibility_clear_all"
         />
 
-    <include layout="@layout/status_bar_flip_button"
-        android:id="@+id/header_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginStart="12dp" />
-</LinearLayout>
+
+
+</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
index b7dff8c..f4d7033 100644
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -15,22 +15,11 @@
   ~ limitations under the License
   -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="50dp"
-        android:layout_height="50dp">
-    <ImageView android:id="@+id/settings_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notify_settings"
-        android:background="@drawable/ic_notify_button_bg"
-        android:contentDescription="@string/accessibility_desc_quick_settings" />
-    <ImageView android:id="@+id/notification_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notifications"
-        android:background="@drawable/ic_notify_button_bg"
-        android:visibility="gone"
-        android:contentDescription="@string/accessibility_notifications_button" />
-</FrameLayout>
\ No newline at end of file
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/settings_button"
+    android:layout_width="50dp"
+    android:layout_height="50dp"
+    android:scaleType="center"
+    android:src="@drawable/ic_notify_quicksettings"
+    android:background="@drawable/ic_notify_button_bg"
+    android:contentDescription="@string/accessibility_desc_quick_settings"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 61d43d7..f9b022c 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -33,11 +33,10 @@
     <com.android.systemui.statusbar.phone.PanelHolder
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/panel_holder_padding_top">
+        android:layout_height="match_parent" >
         <include layout="@layout/status_bar_expanded"
             android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:layout_gravity="start|top" />
     </com.android.systemui.statusbar.phone.PanelHolder>
 
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index c6c0719..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <!-- Layout parameters for the notification panel -->
-	<dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">32dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 92e3885..7372181 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,10 +19,6 @@
     <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
     <dimen name="notification_panel_width">478dp</dimen>
 
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">192dp</dimen>
-    <dimen name="notification_panel_margin_left">16dp</dimen>
-
     <!-- Gravity for the notification panel -->
     <!-- 0x31 = top|center_horizontal -->
     <integer name="notification_panel_layout_gravity">0x31</integer>
@@ -43,9 +39,6 @@
     <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
     <dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
 
-    <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
-    <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
-
     <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
     <item type="dimen" name="notification_panel_min_height_frac">40%</item>
 
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index b1fc00a..a1c5b66 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -24,8 +24,6 @@
 
     <!-- The width of the ticker, including the icon -->
     <dimen name="notification_ticker_width">360dp</dimen>
-    <!-- Status bar panel bottom offset (height of status bar - overlap) -->
-    <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">1dp</dimen>
     <!-- The width of the notification panel window -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c3ccb59..93a75bc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,9 +99,6 @@
 
     <integer name="blinds_pop_duration_ms">10</integer>
 
-    <!-- The device supports quick settings. -->
-    <bool name="config_hasQuickSettings">true</bool>
-
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d763bd6..8d3a565 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -152,21 +152,11 @@
     <!-- Amount of close_handle that will NOT overlap the notification list -->
     <dimen name="close_handle_underlap">32dp</dimen>
 
-    <!-- Height of the notification panel header bar -->
-    <dimen name="notification_panel_header_height">48dp</dimen>
+    <!-- Height of the status bar header bar -->
+    <dimen name="status_bar_header_height">48dp</dimen>
 
-    <!-- Extra space above the panel -->
-    <dimen name="notification_panel_padding_top">0dp</dimen>
-
-    <!-- Extra space above the clock in the panel -->
-    <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
-    <!-- Extra space above the panel holder -->
-    <dimen name="panel_holder_padding_top">0dp</dimen>
-
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">0dp</dimen>
+    <!-- Height of the status bar header bar when expanded -->
+    <dimen name="status_bar_header_height_expanded">144dp</dimen>
 
     <!-- Gravity for the notification panel -->
     <!-- 0x37 = fill_horizontal|top -->
@@ -261,6 +251,9 @@
     <!-- The padding between the individual notification cards. -->
     <dimen name="notification_padding">3dp</dimen>
 
+    <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
+    <dimen name="collapsed_stack_height">94dp</dimen>
+
     <!-- Width of the zen mode interstitial dialog. -->
     <dimen name="zen_mode_dialog_width">320dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d224975..a325186 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1144,7 +1144,6 @@
     protected abstract void updateNotificationIcons();
     protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
     protected abstract void updateExpandedViewPos(int expandedPosition);
-    protected abstract int getExpandedViewMaxHeight();
     protected abstract boolean shouldDisableNavbarGestures();
 
     protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 627b80f..f63ba9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,11 +16,17 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
@@ -29,18 +35,40 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 public class NotificationPanelView extends PanelView implements
-        ExpandableView.OnHeightChangedListener {
+        ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+        View.OnClickListener {
     public static final boolean DEBUG_GESTURES = true;
+    private static final int EXPANSION_ANIMATION_LENGTH = 375;
 
     PhoneStatusBar mStatusBar;
-    private View mHeader;
+    private StatusBarHeaderView mHeader;
+    private QuickSettingsContainerView mQsContainer;
     private View mKeyguardStatusView;
+    private ObservableScrollView mScrollView;
+    private View mStackScrollerContainer;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
-    private boolean mTrackingSettings;
     private int mNotificationTopPadding;
     private boolean mAnimateNextTopPaddingChange;
 
+    private Interpolator mExpansionInterpolator;
+
+    private int mTrackingPointer;
+    private VelocityTracker mVelocityTracker;
+    private boolean mTracking;
+    private boolean mQsExpanded;
+    private float mInitialHeightOnTouch;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private float mQsExpansionHeight;
+    private int mQsMinExpansionHeight;
+    private int mQsMaxExpansionHeight;
+    private int mMinStackHeight;
+    private float mNotificationTranslation;
+    private int mStackScrollerIntrinsicPadding;
+    private boolean mQsExpansionEnabled = true;
+    private ValueAnimator mQsExpansionAnimator;
+
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -63,14 +91,21 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        mHeader = findViewById(R.id.header);
+        mHeader = (StatusBarHeaderView) findViewById(R.id.header);
+        mHeader.getBackgroundView().setOnClickListener(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
+        mStackScrollerContainer = findViewById(R.id.notification_container_parent);
+        mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+        mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
+        mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mNotificationTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.notifications_top_padding);
+        mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+        mExpansionInterpolator = AnimationUtils.loadInterpolator(
+                getContext(), android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
@@ -78,11 +113,21 @@
         super.onLayout(changed, left, top, right, bottom);
         int keyguardBottomMargin =
                 ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
-        mNotificationStackScroller.setTopPadding(mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
-                : mHeader.getBottom() + mNotificationTopPadding,
-                mAnimateNextTopPaddingChange);
-        mAnimateNextTopPaddingChange = false;
+        if (!mQsExpanded) {
+            mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+                    ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
+                    : mHeader.getBottom() + mNotificationTopPadding;
+            mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+                    mAnimateNextTopPaddingChange);
+            mAnimateNextTopPaddingChange = false;
+        }
+
+        // Calculate quick setting heights.
+        mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+        mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
+        if (mQsExpansionHeight == 0) {
+            mQsExpansionHeight = mQsMinExpansionHeight;
+        }
     }
 
     public void animateNextTopPaddingChange() {
@@ -90,6 +135,30 @@
         requestLayout();
     }
 
+    /**
+     * @return Whether Quick Settings are currently expanded.
+     */
+    public boolean isQsExpanded() {
+        return mQsExpanded;
+    }
+
+    public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
+        mQsExpansionEnabled = qsExpansionEnabled;
+        mHeader.setExpansionEnabled(qsExpansionEnabled);
+    }
+
+    public void closeQs() {
+        cancelAnimation();
+        setQsExpansion(mQsMinExpansionHeight);
+    }
+
+    public void openQs() {
+        cancelAnimation();
+        if (mQsExpansionEnabled) {
+            setQsExpansion(mQsMaxExpansionHeight);
+        }
+    }
+
     @Override
     public void fling(float vel, boolean always) {
         GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
@@ -114,42 +183,245 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        // intercept for quick settings
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final View target = mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                    ? mKeyguardStatusView
-                    : mHeader;
-            final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
-            if (inTarget && !isInSettings()) {
-                mTrackingSettings = true;
-                requestDisallowInterceptTouchEvent(true);
-                return true;
-            }
-            if (!inTarget && isInSettings()) {
-                mTrackingSettings = true;
-                requestDisallowInterceptTouchEvent(true);
-                return true;
-            }
+        int pointerIndex = event.findPointerIndex(mTrackingPointer);
+        if (pointerIndex < 0) {
+            pointerIndex = 0;
+            mTrackingPointer = event.getPointerId(pointerIndex);
         }
-        return super.onInterceptTouchEvent(event);
+        final float x = event.getX(pointerIndex);
+        final float y = event.getY(pointerIndex);
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                initVelocityTracker();
+                trackMovement(event);
+                if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+                    getParent().requestDisallowInterceptTouchEvent(true);
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                final int upPointer = event.getPointerId(event.getActionIndex());
+                if (mTrackingPointer == upPointer) {
+                    // gesture is ongoing, find a new pointer to track
+                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                    mTrackingPointer = event.getPointerId(newIndex);
+                    mInitialTouchX = event.getX(newIndex);
+                    mInitialTouchY = event.getY(newIndex);
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                trackMovement(event);
+                if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+                        && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    mTracking = true;
+                    return true;
+                }
+                break;
+        }
+        return !mQsExpanded && super.onInterceptTouchEvent(event);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
         // implementation.
-        if (mTrackingSettings) {
-            mStatusBar.onSettingsEvent(event);
-            if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                mTrackingSettings = false;
+        if (mTracking) {
+            int pointerIndex = event.findPointerIndex(mTrackingPointer);
+            if (pointerIndex < 0) {
+                pointerIndex = 0;
+                mTrackingPointer = event.getPointerId(pointerIndex);
+            }
+            final float y = event.getY(pointerIndex);
+            final float x = event.getX(pointerIndex);
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mTracking = true;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    initVelocityTracker();
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_POINTER_UP:
+                    final int upPointer = event.getPointerId(event.getActionIndex());
+                    if (mTrackingPointer == upPointer) {
+                        // gesture is ongoing, find a new pointer to track
+                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                        final float newY = event.getY(newIndex);
+                        final float newX = event.getX(newIndex);
+                        mTrackingPointer = event.getPointerId(newIndex);
+                        mInitialHeightOnTouch = mQsExpansionHeight;
+                        mInitialTouchY = newY;
+                        mInitialTouchX = newX;
+                    }
+                    break;
+
+                case MotionEvent.ACTION_MOVE:
+                    final float h = y - mInitialTouchY;
+                    setQsExpansion(h + mInitialHeightOnTouch);
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mTracking = false;
+                    mTrackingPointer = -1;
+                    trackMovement(event);
+
+                    float vel = getCurrentVelocity();
+
+                    // TODO: Better logic whether we should expand or not.
+                    flingSettings(vel, vel > 0);
+
+                    if (mVelocityTracker != null) {
+                        mVelocityTracker.recycle();
+                        mVelocityTracker = null;
+                    }
+                    break;
             }
             return true;
         }
-        if (isInSettings()) {
-            return true;
+
+        // Consume touch events when QS are expanded.
+        return mQsExpanded || super.onTouchEvent(event);
+    }
+
+    private void onQsExpansionStarted() {
+        cancelAnimation();
+
+        // Reset scroll position and apply that position to the expanded height.
+        float height = mQsExpansionHeight - mScrollView.getScrollY();
+        mScrollView.scrollTo(0, 0);
+        setQsExpansion(height);
+    }
+
+    private void expandQs() {
+        mHeader.setExpanded(true);
+        mNotificationStackScroller.setEnabled(false);
+        mScrollView.setVisibility(View.VISIBLE);
+        mQsExpanded = true;
+    }
+
+    private void collapseQs() {
+        mHeader.setExpanded(false);
+        mNotificationStackScroller.setEnabled(true);
+        mScrollView.setVisibility(View.INVISIBLE);
+        mQsExpanded = false;
+    }
+
+    private void setQsExpansion(float height) {
+        height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
+        if (height > mQsMinExpansionHeight && !mQsExpanded) {
+            expandQs();
+        } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
+            collapseQs();
         }
-        return super.onTouchEvent(event);
+        mQsExpansionHeight = height;
+        mHeader.setExpansion(height);
+        setQsTranslation(height);
+        setQsStackScrollerPadding(height);
+    }
+
+    private void setQsTranslation(float height) {
+        mQsContainer.setY(height - mQsContainer.getHeight());
+    }
+
+    private void setQsStackScrollerPadding(float height) {
+        float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
+        float stackHeight = mNotificationStackScroller.getHeight() - start;
+        if (stackHeight <= mMinStackHeight) {
+            float overflow = mMinStackHeight - stackHeight;
+            stackHeight = mMinStackHeight;
+            start = mNotificationStackScroller.getHeight() - stackHeight;
+            mNotificationStackScroller.setTranslationY(overflow);
+            mNotificationTranslation = overflow + mScrollView.getScrollY();
+        } else {
+            mNotificationStackScroller.setTranslationY(0);
+            mNotificationTranslation = mScrollView.getScrollY();
+        }
+        mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
+    }
+
+    private int clampQsStackScrollerPadding(int desiredPadding) {
+        return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
+    }
+
+    private void trackMovement(MotionEvent event) {
+        if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+    }
+
+    private void initVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    private float getCurrentVelocity() {
+        if (mVelocityTracker == null) {
+            return 0;
+        }
+        mVelocityTracker.computeCurrentVelocity(1000);
+        return mVelocityTracker.getYVelocity();
+    }
+
+    private void cancelAnimation() {
+        if (mQsExpansionAnimator != null) {
+            mQsExpansionAnimator.cancel();
+        }
+    }
+    private void flingSettings(float vel, boolean expand) {
+
+        // TODO: Actually use velocity.
+
+        float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
+        ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
+        animator.setDuration(EXPANSION_ANIMATION_LENGTH);
+        animator.setInterpolator(mExpansionInterpolator);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setQsExpansion((Float) animation.getAnimatedValue());
+            }
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mQsExpansionAnimator = null;
+            }
+        });
+        animator.start();
+        mQsExpansionAnimator = animator;
+    }
+
+    /**
+     * @return Whether we should intercept a gesture to open Quick Settings.
+     */
+    private boolean shouldIntercept(float x, float y, float yDiff) {
+        if (!mQsExpansionEnabled) {
+            return false;
+        }
+        View headerView = mStatusBar.getBarState() == StatusBarState.KEYGUARD && !mQsExpanded
+                ? mKeyguardStatusView
+                : mHeader;
+        boolean onHeader = x >= headerView.getLeft() && x <= headerView.getRight()
+                && y >= headerView.getTop() && y <= headerView.getBottom();
+        if (mQsExpanded) {
+            return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
+        } else {
+            return onHeader;
+        }
     }
 
     @Override
@@ -164,14 +436,16 @@
     protected int getMaxPanelHeight() {
         if (!isInSettings()) {
             int maxPanelHeight = super.getMaxPanelHeight();
-            int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+            int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
+            int emptyBottomMargin = notificationMarginBottom
+                    + mNotificationStackScroller.getEmptyBottomMargin();
             return maxPanelHeight - emptyBottomMargin;
         }
         return super.getMaxPanelHeight();
     }
 
     private boolean isInSettings() {
-        return mStatusBar != null && mStatusBar.isFlippedToSettings();
+        return mQsExpanded;
     }
 
     @Override
@@ -200,4 +474,24 @@
     public void onHeightChanged(ExpandableView view) {
         requestPanelHeightUpdate();
     }
+
+    @Override
+    public void onScrollChanged() {
+        if (mQsExpanded) {
+            mNotificationStackScroller.setTranslationY(
+                    mNotificationTranslation - mScrollView.getScrollY());
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mHeader.getBackgroundView()) {
+            onQsExpansionStarted();
+            if (mQsExpanded) {
+                flingSettings(0 /* vel */, false /* expand */);
+            } else if (mQsExpansionEnabled) {
+                flingSettings(0 /* vel */, true /* expand */);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
new file mode 100644
index 0000000..f41e78d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 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.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * The container with notification stack scroller and quick settings inside.
+ */
+public class NotificationsQuickSettingsContainer extends FrameLayout {
+
+    public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        setPadding(0, 0, 0, insets.bottom);
+        insets.bottom = 0;
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
new file mode 100644
index 0000000..46484f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 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.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * A scroll view which can be observed for scroll change events.
+ */
+public class ObservableScrollView extends ScrollView {
+
+    private Listener mListener;
+
+    public ObservableScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    public boolean isScrolledToBottom() {
+        return getScrollY() == getMaxScrollY();
+    }
+
+    private int getMaxScrollY() {
+        int scrollRange = 0;
+        if (getChildCount() > 0) {
+            View child = getChildAt(0);
+            scrollRange = Math.max(0,
+                    child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+        }
+        return scrollRange;
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+        if (mListener != null) {
+            mListener.onScrollChanged();
+        }
+    }
+
+    public interface Listener {
+        void onScrollChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0cdca66..c854ac94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -75,7 +75,7 @@
     private boolean mClosing;
     private boolean mTracking;
     private int mTrackingPointer;
-    private int mTouchSlop;
+    protected int mTouchSlop;
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -220,9 +220,9 @@
     private float mVel, mAccel;
     protected int mMaxPanelHeight = 0;
     private String mViewName;
-    protected float mInitialTouchY;
-    protected float mInitialTouchX;
-    protected float mFinalTouchY;
+    private float mInitialTouchY;
+    private float mInitialTouchX;
+    private float mFinalTouchY;
 
     protected void onExpandingFinished() {
     }
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 3856ba1..c4ee6ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -73,7 +73,6 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewPropertyAnimator;
@@ -192,8 +191,6 @@
     int mIconHPadding = -1;
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
-    private float mHeadsUpVerticalOffset;
-    private int[] mStackScrollerPosition = new int[2];
 
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
@@ -222,14 +219,13 @@
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     View mExpandedContents;
     int mNotificationPanelGravity;
-    int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
+    int mNotificationPanelMarginBottomPx;
     float mNotificationPanelMinHeightFrac;
     boolean mNotificationPanelIsFullScreenWidth;
     TextView mNotificationPanelDebugText;
 
     // settings
     QuickSettings mQS;
-    boolean mHasQuickSettings;
     View mFlipSettingsView;
     QuickSettingsContainerView mSettingsContainer;
 
@@ -245,14 +241,14 @@
     int mKeyguardMaxNotificationCount;
     View mDateTimeView;
     View mClearButton;
-    FlipperButton mHeaderFlipper, mKeyguardFlipper;
+    ImageView mHeaderFlipper;
 
     // carrier/wifi label
     private TextView mCarrierLabel;
     private boolean mCarrierLabelVisible = false;
     private int mCarrierLabelHeight;
     private TextView mEmergencyCallLabel;
-    private int mNotificationHeaderHeight;
+    private int mStatusBarHeaderHeight;
     private View mKeyguardCarrierLabel;
 
     private boolean mShowCarrierInPanel = false;
@@ -326,11 +322,12 @@
             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
                     "selfChange=%s userSetup=%s mUserSetup=%s",
                     selfChange, userSetup, mUserSetup));
-            mHeaderFlipper.userSetup(userSetup);
-            mKeyguardFlipper.userSetup(userSetup);
 
             if (userSetup != mUserSetup) {
                 mUserSetup = userSetup;
+                if (mNotificationPanel != null) {
+                    mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
+                }
                 if (!mUserSetup && mStatusBarView != null)
                     animateCollapseQuickSettings();
             }
@@ -651,16 +648,13 @@
         mClearButton.setEnabled(false);
         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
 
-        mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
-
         mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
         if (mDateTimeView != null) {
             mDateTimeView.setOnClickListener(mClockClickListener);
             mDateTimeView.setEnabled(true);
         }
 
-        mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
-        mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
+        mHeaderFlipper = (ImageView) mStatusBarWindow.findViewById(R.id.header_flipper);
 
         if (!mNotificationPanelIsFullScreenWidth) {
             mNotificationPanel.setSystemUiVisibility(
@@ -735,26 +729,23 @@
 //                    updateCarrierLabelVisibility(false);
         }
 
-        // Quick Settings (where available, some restrictions apply)
-        if (mHasQuickSettings) {
-            // Quick Settings needs a container to survive
-            mSettingsContainer = (QuickSettingsContainerView)
-                    mStatusBarWindow.findViewById(R.id.quick_settings_container);
-            mFlipSettingsView = mSettingsContainer;
-            if (mSettingsContainer != null) {
-                mQS = new QuickSettings(mContext, mSettingsContainer);
-                if (!mNotificationPanelIsFullScreenWidth) {
-                    mSettingsContainer.setSystemUiVisibility(
-                            View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
-                            | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
-                }
-                mQS.setService(this);
-                mQS.setBar(mStatusBarView);
-                mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
-                        mLocationController, mRotationLockController);
-            } else {
-                mQS = null; // fly away, be free
+        // Quick Settings needs a container to survive
+        mSettingsContainer = (QuickSettingsContainerView)
+                mStatusBarWindow.findViewById(R.id.quick_settings_container);
+        mFlipSettingsView = mSettingsContainer;
+        if (mSettingsContainer != null) {
+            mQS = new QuickSettings(mContext, mSettingsContainer);
+            if (!mNotificationPanelIsFullScreenWidth) {
+                mSettingsContainer.setSystemUiVisibility(
+                        View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
+                        | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
             }
+            mQS.setService(this);
+            mQS.setBar(mStatusBarView);
+            mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
+                    mLocationController, mRotationLockController);
+        } else {
+            mQS = null; // fly away, be free
         }
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -775,101 +766,6 @@
         return mStatusBarView;
     }
 
-    public boolean onSettingsEvent(MotionEvent event) {
-        userActivity();
-        if (mSettingsClosing
-                && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
-            return true;
-        }
-        if (mSettingsTracker != null) {
-            mSettingsTracker.addMovement(event);
-        }
-        final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            mSettingsTracker = VelocityTracker.obtain();
-            mSettingsDownY = event.getY();
-            mSettingsCancelled = false;
-            mSettingsStarted = false;
-            mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
-            if (mSettingsClosing) {
-                mStackScroller.setVisibility(View.VISIBLE);
-            } else {
-                mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
-            }
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
-                || event.getAction() == MotionEvent.ACTION_CANCEL)) {
-            final float dy = event.getY() - mSettingsDownY;
-            final FlipperButton flipper = mState == StatusBarState.KEYGUARD
-                    ? mKeyguardFlipper
-                    : mHeaderFlipper;
-            final boolean inButton = flipper.inHolderBounds(event);
-            final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
-            if (!qsTap && !inButton) {
-                mSettingsTracker.computeCurrentVelocity(1000);
-                final float vy = mSettingsTracker.getYVelocity();
-                final boolean animate = true;
-                if (dy <= slop || vy <= 0) {
-                    flipToNotifications(animate);
-                } else {
-                    flipToSettings(animate);
-                }
-            }
-            mSettingsTracker.recycle();
-            mSettingsTracker = null;
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
-            final float dy = event.getY() - mSettingsDownY;
-            if (mSettingsClosing) {
-                positionSettings(dy);
-                final boolean qsTap = Math.abs(dy) < slop;
-                if (!mSettingsCancelled && !qsTap) {
-                    MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
-                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
-                    dispatchSettingsEvent(cancelEvent);
-                    mSettingsCancelled = true;
-                }
-            } else {
-                if (!mSettingsStarted && dy > slop) {
-                    mSettingsStarted = true;
-                    mFlipSettingsView.setVisibility(View.VISIBLE);
-                    mStackScroller.setVisibility(View.VISIBLE);
-                }
-                if (mSettingsStarted) {
-                    positionSettings(dy);
-                }
-                dispatchSettingsEvent(event);
-            }
-        }
-        return true;
-    }
-
-    private void dispatchSettingsEvent(MotionEvent event) {
-        final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
-        final int[] targetLoc = new int[2];
-        target.getLocationInWindow(targetLoc);
-        final int[] panelLoc = new int[2];
-        mNotificationPanel.getLocationInWindow(panelLoc);
-        final int dx = targetLoc[0] - panelLoc[0];
-        final int dy = targetLoc[1] - panelLoc[1];
-        event.offsetLocation(-dx, -dy);
-        target.dispatchTouchEvent(event);
-    }
-
-    private void positionSettings(float dy) {
-        if (mSettingsClosing) {
-            final int ph = mNotificationPanel.getMeasuredHeight();
-            dy = Math.min(Math.max(-ph, dy), 0);
-            mFlipSettingsView.setTranslationY(dy);
-            mStackScroller.setTranslationY(ph + dy);
-        } else {
-            final int h = mFlipSettingsView.getBottom();
-            dy = Math.min(Math.max(0, dy), h);
-            mFlipSettingsView.setTranslationY(-h + dy);
-            mStackScroller.setTranslationY(dy);
-        }
-    }
-
     private void startKeyguard() {
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1230,8 +1126,11 @@
             ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
         }
 
-        mHeaderFlipper.refreshLayout();
-        mKeyguardFlipper.refreshLayout();
+        if (mHeaderFlipper != null) {
+            // Force asset reloading
+            mHeaderFlipper.setImageDrawable(null);
+            mHeaderFlipper.setImageResource(R.drawable.ic_notify_quicksettings);
+        }
 
         refreshAllStatusBarIcons();
     }
@@ -1286,8 +1185,7 @@
             }
         }
 
-        mHeaderFlipper.provisionCheck(provisioned);
-        mKeyguardFlipper.provisionCheck(provisioned);
+        mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
     }
 
     @Override
@@ -1362,7 +1260,7 @@
         final boolean makeVisible =
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
-                    - mCarrierLabelHeight - mNotificationHeaderHeight)
+                    - mCarrierLabelHeight - mStatusBarHeaderHeight)
             && mStackScroller.getVisibility() == View.VISIBLE
             && mState != StatusBarState.KEYGUARD;
 
@@ -1775,47 +1673,8 @@
     }
 
     public void flipToNotifications(boolean animate) {
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        cancelAnim(mClearButtonAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        mStackScroller.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY =
-                    mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
-            mScrollViewAnim = start(
-                    interpolator(mDecelerateInterpolator,
-                        ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
-                            .setDuration(FLIP_DURATION)
-                        ));
-            mFlipSettingsViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(
-                                    mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
-                        .setDuration(FLIP_DURATION),
-                    mFlipSettingsView, View.INVISIBLE));
-        } else {
-            mStackScroller.setTranslationY(0);
-            mFlipSettingsView.setTranslationY(-h);
-            mFlipSettingsView.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToNotifications(animate);
-        mKeyguardFlipper.flipToNotifications(animate);
-        mClearButton.setVisibility(View.VISIBLE);
-        mClearButton.setAlpha(0f);
-        setAreThereNotifications(); // this will show/hide the button as necessary
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
+        // TODO: Animation
+        mNotificationPanel.closeQs();
     }
 
     @Override
@@ -1829,78 +1688,18 @@
         if (!mUserSetup) return;
 
         mNotificationPanel.expand();
-        if (mFlipSettingsView.getVisibility() != View.VISIBLE
-                || mFlipSettingsView.getTranslationY() < 0) {
-            flipToSettings(true /*animate*/);
-        }
+        mNotificationPanel.openQs();
 
         if (false) postStartTracing();
     }
 
     public boolean isFlippedToSettings() {
-        if (mFlipSettingsView != null) {
-            return mFlipSettingsView.getVisibility() == View.VISIBLE;
+        if (mNotificationPanel != null) {
+            return mNotificationPanel.isQsExpanded();
         }
         return false;
     }
 
-    public void flipToSettings(boolean animate) {
-        // Settings are not available in setup
-        if (!mUserSetup) return;
-
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        cancelAnim(mClearButtonAnim);
-
-        mFlipSettingsView.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY
-                    = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
-            mFlipSettingsViewAnim = start(
-                    startDelay(0,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
-                                    settingsY, 0f)
-                                .setDuration(FLIP_DURATION)
-                            )));
-            mScrollViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
-                            )
-                        .setDuration(FLIP_DURATION),
-                        mStackScroller, View.INVISIBLE));
-        } else {
-            mFlipSettingsView.setTranslationY(0);
-            mStackScroller.setTranslationY(h);
-            mStackScroller.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToSettings(animate);
-        mKeyguardFlipper.flipToSettings(animate);
-        if (animate) {
-            mClearButtonAnim = start(
-                setVisibilityWhenDone(
-                    ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
-                    .setDuration(FLIP_DURATION),
-                    mClearButton, View.INVISIBLE));
-        } else {
-            mClearButton.setAlpha(0);
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
-    }
-
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
@@ -1927,12 +1726,10 @@
 
         mStackScroller.setVisibility(View.VISIBLE);
         mNotificationPanel.setVisibility(View.GONE);
-        mFlipSettingsView.setVisibility(View.GONE);
 
         setAreThereNotifications(); // show the clear button
 
-        mHeaderFlipper.reset();
-        mKeyguardFlipper.reset();
+        mNotificationPanel.closeQs();
 
         mExpandedVisible = false;
         if (mNavigationBarView != null)
@@ -2463,20 +2260,11 @@
         }
     }
 
-    void updateExpandedInvisiblePosition() {
-        mTrackingPosition = -mDisplayMetrics.heightPixels;
-    }
-
     static final float saturate(float a) {
         return a < 0f ? 0f : (a > 1f ? 1f : a);
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
-    }
-
-    @Override
     public void updateExpandedViewPos(int thingy) {
         if (SPEW) Log.v(TAG, "updateExpandedViewPos");
 
@@ -2486,15 +2274,8 @@
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
         lp.gravity = mNotificationPanelGravity;
-        lp.setMarginStart(mNotificationPanelMarginPx);
         mNotificationPanel.setLayoutParams(lp);
 
-        if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
-            mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
-            mStackScroller.getLocationOnScreen(mStackScrollerPosition);
-            mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
-        }
-
         updateCarrierLabelVisibility(false);
     }
 
@@ -2542,17 +2323,6 @@
         animateCollapsePanels();
     }
 
-    private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            if (mHasQuickSettings) {
-                animateExpandSettingsPanel();
-            } else {
-                startActivityDismissingKeyguard(
-                        new Intent(android.provider.Settings.ACTION_SETTINGS), true);
-            }
-        }
-    };
-
     private View.OnClickListener mClockClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             startActivityDismissingKeyguard(
@@ -2653,17 +2423,6 @@
         }
     }
 
-    public void animateHeadsUp(boolean animateInto, float frac) {
-        if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
-        frac = frac / 0.4f;
-        frac = frac < 1.0f ? frac : 1.0f;
-        float alpha = 1.0f - frac;
-        float offset = mHeadsUpVerticalOffset * frac;
-        offset = animateInto ? offset : 0f;
-        mHeadsUpNotificationView.setAlpha(alpha);
-        mHeadsUpNotificationView.setY(offset);
-    }
-
     public void onHeadsUpDismissed() {
         if (mInterruptingNotificationEntry == null) return;
         mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
@@ -2736,17 +2495,13 @@
 
         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
 
-        mNotificationPanelMarginBottomPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
-        mNotificationPanelMarginPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_left);
         mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
         if (mNotificationPanelGravity <= 0) {
             mNotificationPanelGravity = Gravity.START | Gravity.TOP;
         }
 
         mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
-        mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
+        mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
 
         mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
         if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
@@ -3016,9 +2771,6 @@
 
     private void updateKeyguardState() {
         if (mState == StatusBarState.KEYGUARD) {
-            if (isFlippedToSettings()) {
-                flipToNotifications(false /*animate*/);
-            }
             mKeyguardStatusView.setVisibility(View.VISIBLE);
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
@@ -3026,7 +2778,7 @@
             mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
             mNotificationPanelHeader.setVisibility(View.GONE);
 
-            mKeyguardFlipper.setVisibility(View.VISIBLE);
+            mNotificationPanel.closeQs();
             mSettingsContainer.setKeyguardShowing(true);
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
@@ -3035,7 +2787,6 @@
             mKeyguardCarrierLabel.setVisibility(View.GONE);
             mNotificationPanelHeader.setVisibility(View.VISIBLE);
 
-            mKeyguardFlipper.setVisibility(View.GONE);
             mSettingsContainer.setKeyguardShowing(false);
         }
 
@@ -3202,131 +2953,6 @@
      * @return a ViewGroup that spans the entire panel which contains the quick settings
      */
     public ViewGroup getQuickSettingsOverlayParent() {
-        if (mHasQuickSettings) {
-            return mNotificationPanel;
-        } else {
-            return null;
-        }
-    }
-
-    public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
-        final int[] location = new int[2];
-        view.getLocationInWindow(location);
-        final int rx = (int) event.getRawX();
-        final int ry = (int) event.getRawY();
-        return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
-                && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
-    }
-
-    private final class FlipperButton {
-        private final View mHolder;
-
-        private ImageView mSettingsButton, mNotificationButton;
-        private Animator mSettingsButtonAnim, mNotificationButtonAnim;
-
-        public FlipperButton(View holder) {
-            mHolder = holder;
-            mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
-            if (mSettingsButton != null) {
-                mSettingsButton.setOnClickListener(mSettingsButtonListener);
-                if (mHasQuickSettings) {
-                    // the settings panel is hiding behind this button
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                } else {
-                    // no settings panel, go straight to settings
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
-                }
-            }
-            mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
-            if (mNotificationButton != null) {
-                mNotificationButton.setOnClickListener(mNotificationButtonListener);
-            }
-        }
-
-        public boolean inHolderBounds(MotionEvent event) {
-            return inBounds(mHolder, event, false);
-        }
-
-        public void provisionCheck(boolean provisioned) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setEnabled(provisioned);
-            }
-        }
-
-        public void userSetup(boolean userSetup) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
-            }
-        }
-
-        public void reset() {
-            cancel();
-            mSettingsButton.setVisibility(View.VISIBLE);
-            mNotificationButton.setVisibility(View.GONE);
-        }
-
-        public void refreshLayout() {
-            if (mSettingsButton != null) {
-                // Force asset reloading
-                mSettingsButton.setImageDrawable(null);
-                mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-            }
-
-            if (mNotificationButton != null) {
-                // Force asset reloading
-                mNotificationButton.setImageDrawable(null);
-                mNotificationButton.setImageResource(R.drawable.ic_notifications);
-            }
-        }
-
-        public void flipToSettings(boolean animate) {
-            mNotificationButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mSettingsButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mStackScroller, View.INVISIBLE));
-                mNotificationButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mSettingsButton.setAlpha(0f);
-                mSettingsButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(1f);
-            }
-        }
-
-        public void flipToNotifications(boolean animate) {
-            mSettingsButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mNotificationButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mNotificationButton, View.INVISIBLE));
-
-                mSettingsButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mNotificationButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(0f);
-                mSettingsButton.setAlpha(1f);
-            }
-        }
-
-        public void cancel() {
-            cancelAnim(mSettingsButtonAnim);
-            cancelAnim(mNotificationButtonAnim);
-        }
-
-        public void setVisibility(int vis) {
-            mHolder.setVisibility(vis);
-        }
+        return mNotificationPanel;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 10c1625..e6de057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -220,8 +220,6 @@
             panel.setAlpha(alpha);
         }
 
-        mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
-
         mBar.updateCarrierLabelVisibility(false);
         mBar.userActivity();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
new file mode 100644
index 0000000..9d33930
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+
+/**
+ * The view to manage the header area in the expanded status bar.
+ */
+public class StatusBarHeaderView extends RelativeLayout {
+
+    private boolean mExpanded;
+    private View mBackground;
+    private View mFlipper;
+
+    private int mCollapsedHeight;
+    private int mExpandedHeight;
+
+    public StatusBarHeaderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBackground = findViewById(R.id.background);
+        mFlipper = findViewById(R.id.header_flipper);
+        loadDimens();
+    }
+
+    private void loadDimens() {
+        mCollapsedHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height);
+        mExpandedHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height_expanded);
+    }
+
+    public int getCollapsedHeight() {
+        return mCollapsedHeight;
+    }
+
+    public int getExpandedHeight() {
+        return mExpandedHeight;
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (expanded != mExpanded) {
+            ViewGroup.LayoutParams lp = getLayoutParams();
+            lp.height = expanded ? mExpandedHeight : mCollapsedHeight;
+            setLayoutParams(lp);
+            mExpanded = expanded;
+        }
+    }
+
+    public void setExpansionEnabled(boolean enabled) {
+        mFlipper.setVisibility(enabled ? View.VISIBLE : View.GONE);
+    }
+
+    public void setExpansion(float height) {
+        if (height < mCollapsedHeight) {
+            height = mCollapsedHeight;
+        }
+        if (height > mExpandedHeight) {
+            height = mExpandedHeight;
+        }
+        if (mExpanded) {
+            mBackground.setTranslationY(-(mExpandedHeight - height));
+        } else {
+            mBackground.setTranslationY(0);
+        }
+    }
+
+    public View getBackgroundView() {
+        return mBackground;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 4c9264d..e802d185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -56,11 +56,14 @@
     @Override
     protected boolean fitSystemWindows(Rect insets) {
         if (getFitsSystemWindows()) {
-            setPadding(insets.left, insets.top, insets.right, insets.bottom);
+            setPadding(insets.left, insets.top, insets.right, 0);
+            insets.left = 0;
+            insets.top = 0;
+            insets.right = 0;
         } else {
             setPadding(0, 0, 0, 0);
         }
-        return true;
+        return false;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index f8aab80..59d717c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -492,6 +492,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        if (!isEnabled()) {
+            return false;
+        }
         boolean scrollerWantsIt = false;
         if (!mSwipingInProgress) {
             scrollerWantsIt = onScrollTouch(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 4b3d3b0..d6a8885 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -121,11 +121,6 @@
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return 0;
-    }
-
-    @Override
     protected boolean shouldDisableNavbarGestures() {
         return true;
     }