Updated QS UI

 - Adds footer to QS which contains the date/alarm info
   and all touch targets (settings, edit, etc.)
 - Swaps out emergency + carrier text on cell tile for a
   standard CarrierText from lock screen in the header
   to make the header only contain status info.
 - Add dividing line
 - Work on animations

Test: runtest systemui
Change-Id: I97dfea1b1ea7006b53eb61ac3a1f942c64dd282d
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
new file mode 100644
index 0000000..f6f8f53
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.plugins.qs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(version = DetailAdapter.VERSION)
+public interface DetailAdapter {
+    public static final int VERSION = 1;
+
+    CharSequence getTitle();
+    Boolean getToggleState();
+
+    default boolean getToggleEnabled() {
+        return true;
+    }
+
+    View createDetailView(Context context, View convertView, ViewGroup parent);
+    Intent getSettingsIntent();
+    void setToggleState(boolean state);
+    int getMetricsCategory();
+
+    /**
+     * Indicates whether the detail view wants to have its header (back button, title and
+     * toggle) shown.
+     */
+    default boolean hasHeader() {
+        return true;
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index b7467eb..4a5a681 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,58 +14,53 @@
 
 package com.android.systemui.plugins.qs;
 
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+
 import com.android.systemui.plugins.FragmentBase;
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.plugins.qs.QS.Callback;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.plugins.qs.QS.HeightListener;
 
-import android.content.Context;
-import android.content.Intent;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RelativeLayout;
-
 /**
  * Fragment that contains QS in the notification shade.  Most of the interface is for
  * handling the expand/collapsing of the view interaction.
  */
 @ProvidesInterface(action = QS.ACTION, version = QS.VERSION)
 @DependsOn(target = HeightListener.class)
-@DependsOn(target = Callback.class)
-@DependsOn(target = DetailAdapter.class)
 public interface QS extends FragmentBase {
 
     public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
 
-    public static final int VERSION = 5;
+    public static final int VERSION = 6;
 
     String TAG = "QS";
 
-    public abstract void setPanelView(HeightListener notificationPanelView);
-    public abstract BaseStatusBarHeader getHeader();
+    void setPanelView(HeightListener notificationPanelView);
 
-    public abstract void hideImmediately();
-    public abstract int getQsMinExpansionHeight();
-    public abstract int getDesiredHeight();
-    public abstract void setHeightOverride(int desiredHeight);
-    public abstract void setHeaderClickable(boolean qsExpansionEnabled);
-    public abstract boolean isCustomizing();
-    public abstract void setOverscrolling(boolean overscrolling);
-    public abstract void setExpanded(boolean qsExpanded);
-    public abstract void setListening(boolean listening);
-    public abstract boolean isShowingDetail();
-    public abstract void closeDetail();
-    public abstract void setKeyguardShowing(boolean keyguardShowing);
-    public abstract void animateHeaderSlidingIn(long delay);
-    public abstract void animateHeaderSlidingOut();
-    public abstract void setQsExpansion(float qsExpansionFraction, float headerTranslation);
-    public abstract void setHeaderListening(boolean listening);
-    public abstract void notifyCustomizeChanged();
+    void hideImmediately();
+    int getQsMinExpansionHeight();
+    int getDesiredHeight();
+    void setHeightOverride(int desiredHeight);
+    void setHeaderClickable(boolean qsExpansionEnabled);
+    boolean isCustomizing();
+    void setOverscrolling(boolean overscrolling);
+    void setExpanded(boolean qsExpanded);
+    void setListening(boolean listening);
+    boolean isShowingDetail();
+    void closeDetail();
+    void setKeyguardShowing(boolean keyguardShowing);
+    void animateHeaderSlidingIn(long delay);
+    void animateHeaderSlidingOut();
+    void setQsExpansion(float qsExpansionFraction, float headerTranslation);
+    void setHeaderListening(boolean listening);
+    void notifyCustomizeChanged();
 
-    public abstract void setContainer(ViewGroup container);
+    void setContainer(ViewGroup container);
+    void setExpandClickListener(OnClickListener onClickListener);
+
+    View getHeader();
 
     @ProvidesInterface(version = HeightListener.VERSION)
     public interface HeightListener {
@@ -73,51 +68,4 @@
         void onQsHeightChanged();
     }
 
-    @ProvidesInterface(version = Callback.VERSION)
-    public interface Callback {
-        public static final int VERSION = 1;
-        void onShowingDetail(DetailAdapter detail, int x, int y);
-        void onToggleStateChanged(boolean state);
-        void onScanStateChanged(boolean state);
-    }
-
-    @ProvidesInterface(version = DetailAdapter.VERSION)
-    public interface DetailAdapter {
-        public static final int VERSION = 1;
-        CharSequence getTitle();
-        Boolean getToggleState();
-        default boolean getToggleEnabled() {
-            return true;
-        }
-        View createDetailView(Context context, View convertView, ViewGroup parent);
-        Intent getSettingsIntent();
-        void setToggleState(boolean state);
-        int getMetricsCategory();
-
-        /**
-         * Indicates whether the detail view wants to have its header (back button, title and
-         * toggle) shown.
-         */
-        default boolean hasHeader() { return true; }
-    }
-
-    @ProvidesInterface(version = BaseStatusBarHeader.VERSION)
-    public abstract static class BaseStatusBarHeader extends RelativeLayout {
-        public static final int VERSION = 1;
-
-        public BaseStatusBarHeader(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public abstract int getCollapsedHeight();
-        public abstract int getExpandedHeight();
-
-        public abstract void setExpanded(boolean b);
-        public abstract void setExpansion(float headerExpansionFraction);
-        public abstract void setListening(boolean listening);
-        public abstract void updateEverything();
-        public abstract void setCallback(Callback qsPanelCallback);
-        public abstract View getExpandView();
-    }
-
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 887dafc..7bb31c0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -20,7 +20,6 @@
 
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.Callback;
 import com.android.systemui.plugins.qs.QSTile.Icon;
 import com.android.systemui.plugins.qs.QSTile.State;
diff --git a/packages/SystemUI/res/drawable/ic_settings_20dp.xml b/packages/SystemUI/res/drawable/ic_settings_16dp.xml
similarity index 96%
rename from packages/SystemUI/res/drawable/ic_settings_20dp.xml
rename to packages/SystemUI/res/drawable/ic_settings_16dp.xml
index 3170f86..c21b60c 100644
--- a/packages/SystemUI/res/drawable/ic_settings_20dp.xml
+++ b/packages/SystemUI/res/drawable/ic_settings_16dp.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="20dp"
-    android:height="20dp"
+    android:width="16dp"
+    android:height="16dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_sim.xml b/packages/SystemUI/res/drawable/ic_sim.xml
new file mode 100644
index 0000000..983c1d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sim.xml
@@ -0,0 +1,27 @@
+<!--
+    Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M0 0h24v24H0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M18.0,2.0l-8.0,0.0L4.02,8.0 4.0,20.0c0.0,1.0 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml b/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml
deleted file mode 100644
index 46c761a..0000000
--- a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/date_time_alarm_group"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_marginTop="16dp"
-    android:layout_marginStart="16dp"
-    android:gravity="start"
-    android:orientation="vertical">
-    <LinearLayout
-        android:id="@+id/date_time_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:focusable="true" >
-
-        <include layout="@layout/split_clock_view"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:id="@+id/clock" />
-
-        <com.android.systemui.statusbar.policy.DateView
-            android:id="@+id/date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="6dp"
-            android:drawableStart="@drawable/header_dot"
-            android:drawablePadding="6dp"
-            android:singleLine="true"
-            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-            android:textSize="@dimen/qs_time_collapsed_size"
-            android:gravity="top"
-            systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
-
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@+id/alarm_status_collapsed"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:src="@drawable/ic_access_alarms_small"
-            android:paddingStart="6dp"
-            android:gravity="center"
-            android:visibility="gone" />
-    </LinearLayout>
-
-    <com.android.systemui.statusbar.AlphaOptimizedButton
-        android:id="@+id/alarm_status"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:minHeight="20dp"
-        android:paddingTop="3dp"
-        android:drawablePadding="8dp"
-        android:drawableStart="@drawable/ic_access_alarms_small"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-        android:gravity="top"
-        android:background="?android:attr/selectableItemBackground"
-        android:visibility="gone" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_divider.xml b/packages/SystemUI/res/layout/qs_divider.xml
new file mode 100644
index 0000000..660e4af
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="1dp"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:background="?android:attr/colorForeground" />
diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer.xml
new file mode 100644
index 0000000..82e1ae7
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_footer.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** 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.
+-->
+
+<!-- Extends RelativeLayout -->
+<com.android.systemui.qs.QSFooter
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/header"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:baselineAligned="false"
+    android:clickable="false"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:paddingTop="0dp"
+    android:paddingEnd="8dp"
+    android:paddingStart="16dp"
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
+
+    <include
+        android:id="@+id/date_time_alarm_group"
+        layout="@layout/status_bar_alarm_group"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+
+    <com.android.systemui.statusbar.phone.MultiUserSwitch
+        android:id="@+id/multi_user_switch"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_alignParentEnd="true"
+        android:background="@drawable/ripple_drawable"
+        android:focusable="true">
+
+        <ImageView
+            android:id="@+id/multi_user_avatar"
+            android:layout_width="@dimen/multi_user_avatar_expanded_size"
+            android:layout_height="@dimen/multi_user_avatar_expanded_size"
+            android:layout_gravity="center"
+            android:scaleType="centerInside"/>
+    </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:id="@android:id/edit"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:background="?android:attr/selectableItemBackgroundBorderless"
+        android:clickable="true"
+        android:clipToPadding="false"
+        android:contentDescription="@string/accessibility_quick_settings_edit"
+        android:focusable="true"
+        android:padding="16dp"
+        android:src="@drawable/ic_mode_edit"
+        android:tint="?android:attr/colorForeground"/>
+
+    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+        android:id="@+id/settings_button_container"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:clipChildren="false"
+        android:clipToPadding="false">
+
+        <com.android.systemui.statusbar.phone.SettingsButton
+            android:id="@+id/settings_button"
+            style="@android:style/Widget.Material.Button.Borderless"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/ripple_drawable"
+            android:contentDescription="@string/accessibility_quick_settings_settings"
+            android:src="@drawable/ic_settings_16dp"
+            android:tint="?android:attr/colorForeground"/>
+
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:id="@+id/tuner_icon"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingStart="36dp"
+            android:paddingEnd="4dp"
+            android:src="@drawable/tuner"
+            android:tint="?android:attr/textColorTertiary"
+            android:visibility="invisible"/>
+
+    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+    <com.android.systemui.statusbar.phone.ExpandableIndicator
+        android:id="@+id/expand_indicator"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:clipToPadding="false"
+        android:clickable="true"
+        android:focusable="true"
+        android:background="?android:attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/accessibility_quick_settings_expand"
+        android:padding="14dp" />
+
+</com.android.systemui.qs.QSFooter>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 895185b..3658313 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -26,12 +26,16 @@
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
             android:background="#0000"
-            android:layout_marginTop="52dp"
+            android:layout_marginTop="28dp"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="48dp" />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
+    <include android:id="@+id/qs_footer"
+        layout="@layout/qs_footer" />
+
     <include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
 
     <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 78d4bdd..520dab4 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -16,8 +16,9 @@
 -->
 
 <!-- Extends RelativeLayout -->
-<com.android.systemui.statusbar.phone.QuickStatusBarHeader
+<com.android.systemui.qs.QuickStatusBarHeader
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/header"
     android:layout_width="match_parent"
     android:layout_height="@dimen/status_bar_header_height"
@@ -26,147 +27,71 @@
     android:clickable="false"
     android:clipChildren="false"
     android:clipToPadding="false"
+    android:paddingBottom="48dp"
     android:paddingTop="0dp"
     android:paddingEnd="0dp"
     android:paddingStart="0dp">
 
     <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
+        android:layout_width="match_parent"
+        android:layout_height="24dp"
         android:layout_alignParentEnd="true"
         android:clipChildren="false"
         android:clipToPadding="false"
         android:gravity="center"
-        android:paddingEnd="4dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
         android:orientation="horizontal">
 
-        <com.android.systemui.statusbar.phone.MultiUserSwitch
-            android:id="@+id/multi_user_switch"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:layout_alignParentEnd="true"
-            android:background="@drawable/ripple_drawable"
-            android:focusable="true">
 
-            <ImageView
-                android:id="@+id/multi_user_avatar"
-                android:layout_width="@dimen/multi_user_avatar_expanded_size"
-                android:layout_height="@dimen/multi_user_avatar_expanded_size"
-                android:layout_gravity="center"
-                android:scaleType="centerInside"/>
-        </com.android.systemui.statusbar.phone.MultiUserSwitch>
+        <com.android.keyguard.CarrierText
+            android:id="@+id/qs_carrier_text"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center_vertical|start"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorPrimary"
+            android:singleLine="true" />
 
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@android:id/edit"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:background="?android:attr/selectableItemBackgroundBorderless"
-            android:clickable="true"
-            android:clipToPadding="false"
-            android:contentDescription="@string/accessibility_quick_settings_edit"
-            android:focusable="true"
-            android:padding="14dp"
-            android:src="@drawable/ic_mode_edit"
-            android:tint="?android:attr/colorForeground"/>
-
-        <LinearLayout
-            android:id="@+id/system_icons_super_container"
+        <FrameLayout
+            android:id="@+id/system_icons_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/status_bar_header_height"
-            android:layout_alignWithParentIfMissing="true"
-            android:layout_toStartOf="@id/multi_user_switch"
-            android:background="@drawable/ripple_drawable">
+            android:layout_height="match_parent"
+            android:layout_gravity="center_vertical">
 
-            <FrameLayout
-                android:id="@+id/system_icons_container"
-                android:layout_width="wrap_content"
-                android:layout_height="24dp"
-                android:layout_gravity="center_vertical">
+            <include layout="@layout/system_icons" />
 
-                <include layout="@layout/system_icons" />
-            </FrameLayout>
-        </LinearLayout>
+        </FrameLayout>
 
-        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-            android:id="@+id/settings_button_container"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:clipChildren="false"
-            android:clipToPadding="false">
-
-            <com.android.systemui.statusbar.phone.SettingsButton
-                android:id="@+id/settings_button"
-                style="@android:style/Widget.Material.Button.Borderless"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="@drawable/ripple_drawable"
-                android:contentDescription="@string/accessibility_quick_settings_settings"
-                android:src="@drawable/ic_settings_20dp"
-                android:tint="?android:attr/colorForeground"/>
-
-            <com.android.systemui.statusbar.AlphaOptimizedImageView
-                android:id="@+id/tuner_icon"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:paddingStart="36dp"
-                android:src="@drawable/tuner"
-                android:tint="?android:attr/textColorTertiary"
-                android:visibility="invisible"/>
-
-        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
-        <com.android.systemui.statusbar.phone.ExpandableIndicator
-            android:id="@+id/expand_indicator"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:clipToPadding="false"
-            android:clickable="true"
-            android:focusable="true"
-            android:background="?android:attr/selectableItemBackgroundBorderless"
-            android:contentDescription="@string/accessibility_quick_settings_expand"
-            android:padding="12dp" />
-
+        <com.android.systemui.statusbar.policy.Clock
+            android:id="@+id/clock"
+            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:singleLine="true"
+            android:paddingStart="@dimen/status_bar_clock_starting_padding"
+            android:paddingEnd="@dimen/status_bar_clock_end_padding"
+            android:gravity="center_vertical|start"
+            systemui:showDark="false"
+            />
     </LinearLayout>
 
-    <TextView
-        android:id="@+id/header_emergency_calls_only"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
-        android:focusable="true"
-        android:gravity="center_vertical"
-        android:paddingStart="16dp"
-        android:paddingTop="6dp"
-        android:singleLine="true"
-        android:text="@*android:string/emergency_calls_only"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
-        android:visibility="gone"/>
-
-    <include
-        android:id="@+id/date_time_alarm_group"
-        layout="@layout/status_bar_alarm_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_marginTop="12dp"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true" />
-
     <com.android.systemui.qs.QuickQSPanel
         android:id="@+id/quick_qs_panel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentEnd="true"
-        android:layout_marginTop="54dp"
-        android:layout_marginBottom="24dp"
+        android:layout_marginTop="36dp"
+        android:layout_marginBottom="8dp"
         android:layout_alignParentTop="true"
         android:accessibilityTraversalAfter="@+id/date_time_group"
         android:accessibilityTraversalBefore="@id/expand_indicator"
         android:clipChildren="false"
         android:clipToPadding="false"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
         android:focusable="true"
         android:importantForAccessibility="yes"
         android:paddingTop="0dp"/>
@@ -192,4 +117,4 @@
         android:textStyle="bold"
         android:visibility="invisible"/>
 
-</com.android.systemui.statusbar.phone.QuickStatusBarHeader>
+</com.android.systemui.qs.QuickStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/status_bar_alarm_group.xml b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
index 745320e..7a5b6dc 100644
--- a/packages/SystemUI/res/layout/status_bar_alarm_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
@@ -18,57 +18,42 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/date_time_alarm_group"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_marginTop="16dp"
-    android:layout_marginStart="16dp"
-    android:gravity="start"
-    android:orientation="vertical">
-    <LinearLayout
-        android:id="@+id/date_time_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:focusable="true" >
-
-        <include layout="@layout/split_clock_view"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:id="@+id/clock" />
-
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@+id/alarm_status_collapsed"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:src="@drawable/ic_access_alarms_small"
-            android:tint="?android:attr/textColorPrimary"
-            android:paddingStart="6dp"
-            android:gravity="center"
-            android:visibility="gone" />
-    </LinearLayout>
+    android:layout_width="0dp"
+    android:layout_height="48dp"
+    android:layout_weight="1"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:background="?android:attr/selectableItemBackground">
 
     <com.android.systemui.statusbar.policy.DateView
         android:id="@+id/date"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
         android:singleLine="true"
-        android:layout_marginTop="-4dp"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
         android:textSize="@dimen/qs_time_collapsed_size"
-        android:gravity="top"
+        android:gravity="center_vertical"
         systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
 
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:id="@+id/alarm_status_collapsed"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:src="@drawable/ic_access_alarms_small"
+        android:tint="?android:attr/textColorPrimary"
+        android:paddingStart="6dp"
+        android:paddingEnd="6dp"
+        android:gravity="center"
+        android:visibility="gone" />
+
     <com.android.systemui.statusbar.AlphaOptimizedButton
         android:id="@+id/alarm_status"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:minHeight="20dp"
-        android:paddingTop="3dp"
-        android:drawablePadding="8dp"
-        android:drawableStart="@drawable/ic_access_alarms_small"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-        android:gravity="top"
-        android:background="?android:attr/selectableItemBackground"
+        android:layout_height="match_parent"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:gravity="center_vertical"
+        android:background="@null"
+        android:clickable="false"
         android:visibility="gone" />
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 7632f87..f405943 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -50,6 +50,7 @@
             <enum name="small" value="1" />
             <enum name="gone" value="2" />
         </attr>
+        <attr name="showDark" format="boolean" />
     </declare-styleable>
     <attr name="orientation">
         <enum name="horizontal" value="0" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f42344e..3512761 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -179,10 +179,10 @@
     <dimen name="close_handle_underlap">32dp</dimen>
 
     <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">126dp</dimen>
+    <dimen name="status_bar_header_height">124dp</dimen>
 
     <!-- Height of the status bar header bar when expanded -->
-    <dimen name="status_bar_header_height_expanded">116dp</dimen>
+    <dimen name="status_bar_header_height_expanded">124dp</dimen>
 
     <!-- Height of the status bar header bar when on Keyguard -->
     <dimen name="status_bar_header_height_keyguard">40dp</dimen>
@@ -238,7 +238,7 @@
     <dimen name="qs_tile_padding_below_icon">12dp</dimen>
     <dimen name="qs_tile_padding_bottom">16dp</dimen>
     <dimen name="qs_tile_spacing">4dp</dimen>
-    <dimen name="qs_panel_padding_bottom">8dp</dimen>
+    <dimen name="qs_panel_padding_bottom">0dp</dimen>
     <dimen name="qs_detail_header_height">56dp</dimen>
     <dimen name="qs_detail_header_padding">0dp</dimen>
     <dimen name="qs_detail_header_bottom_padding">0dp</dimen>
@@ -428,7 +428,7 @@
     <dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
 
     <!-- The width of user avatar when expanded -->
-    <dimen name="multi_user_avatar_expanded_size">24dp</dimen>
+    <dimen name="multi_user_avatar_expanded_size">16dp</dimen>
 
     <!-- The font size of the time when collapsed in QS -->
     <dimen name="qs_time_collapsed_size">14sp</dimen>
@@ -731,4 +731,7 @@
     <!-- The size of the PIP drag-to-dismiss target. -->
     <dimen name="pip_dismiss_target_size">48dp</dimen>
 
+    <dimen name="default_gear_space">18dp</dimen>
+    <dimen name="cell_overlay_padding">18dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 815c41f..62e11f7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1819,4 +1819,7 @@
     <!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
     <string name="app_info">App info</string>
 
+    <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
+    <string name="mobile_data">Mobile data</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 411fd3d..af7e9b4 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -35,7 +35,7 @@
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index 58670da..79f78c9 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -358,7 +358,7 @@
                             + ", expected " + mVersion);
                     return null;
                 }
-            } catch (Exception e) {
+            } catch (Throwable e) {
                 Log.w(TAG, "Couldn't load plugin: " + pkg, e);
                 return null;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
new file mode 100644
index 0000000..7fe28c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.qs;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.ImageView;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon;
+
+// Exists to provide easy way to add sim icon to cell tile
+// TODO Find a better way to handle this and remove it.
+public class CellTileView extends SignalTileView {
+
+    private final ImageView mOverlay;
+
+    public CellTileView(Context context) {
+        super(context);
+        mOverlay = new ImageView(mContext);
+        mOverlay.setImageTintList(ColorStateList.valueOf(Utils.getColorAttr(context,
+                android.R.attr.colorPrimary)));
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT);
+        int padding = context.getResources().getDimensionPixelOffset(R.dimen.cell_overlay_padding);
+        params.leftMargin = params.rightMargin = padding;
+        mIconFrame.addView(mOverlay, params);
+    }
+
+    @Override
+    public void setIcon(State state) {
+        State s = state.copy();
+        updateIcon(mOverlay, state);
+        s.icon = ResourceIcon.get(R.drawable.ic_sim);
+        super.setIcon(s);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 5d3effc..3337090 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -27,7 +27,6 @@
 import com.android.systemui.qs.QSHost.Callback;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.qs.TouchAnimator.Listener;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -162,7 +161,9 @@
 
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         mAllViews.add((View) tileLayout);
-        firstPageBuilder.addFloat(tileLayout, "translationY", mQsPanel.getHeight(), 0);
+        int heightDiff = mQsPanel.getBottom() - mQs.getHeader().getBottom()
+                + mQs.getHeader().getPaddingBottom();
+        firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
 
         for (QSTile tile : tiles) {
             QSTileView tileView = mQsPanel.getTileView(tile);
@@ -208,7 +209,7 @@
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
 
-                firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                firstPageBuilder.addFloat(tileView, "translationY", heightDiff, 0);
                 translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
                 translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
                 translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
@@ -216,7 +217,7 @@
                 mAllViews.add(tileIcon);
             } else {
                 firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
-                firstPageBuilder.addFloat(tileView, "translationY", -mQsPanel.getHeight(), 0);
+                firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
             }
             mAllViews.add(tileView);
             count++;
@@ -225,12 +226,15 @@
             // Make brightness appear static position and alpha in through second half.
             View brightness = mQsPanel.getBrightnessView();
             if (brightness != null) {
-                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
+                firstPageBuilder.addFloat(brightness, "translationY", heightDiff, 0);
                 mBrightnessAnimator = new TouchAnimator.Builder()
                         .addFloat(brightness, "alpha", 0, 1)
                         .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
+                        .addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
                         .setStartDelay(.5f)
                         .build();
+                mAllViews.add(mQsPanel.getPageIndicator());
+                mAllViews.add(mQsPanel.getDivider());
                 mAllViews.add(brightness);
             } else {
                 mBrightnessAnimator = null;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 91b4d0d..06264ba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -38,6 +38,7 @@
     protected View mHeader;
     protected float mQsExpansion;
     private QSCustomizer mQSCustomizer;
+    private QSFooter mQSFooter;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -49,7 +50,8 @@
         mQSPanel = findViewById(R.id.quick_settings_panel);
         mQSDetail = findViewById(R.id.qs_detail);
         mHeader = findViewById(R.id.header);
-        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
+        mQSCustomizer = findViewById(R.id.qs_customize);
+        mQSFooter = findViewById(R.id.qs_footer);
     }
 
     @Override
@@ -60,7 +62,8 @@
         mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
                 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
         int width = mQSPanel.getMeasuredWidth();
-        int height = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+        LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
+        int height = layoutParams.topMargin + layoutParams.bottomMargin
                 + mQSPanel.getMeasuredHeight();
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
@@ -93,6 +96,8 @@
         int height = calculateContainerHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
+        // Pin QS Footer to the bottom of the panel.
+        mQSFooter.setTranslationY(height - mQSFooter.getHeight());
     }
 
     protected int calculateContainerHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 7df124a..1709718 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -38,11 +38,8 @@
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QS.Callback;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class QSDetail extends LinearLayout {
 
@@ -68,7 +65,7 @@
     private boolean mScanState;
     private boolean mClosingDetail;
     private boolean mFullyExpanded;
-    private BaseStatusBarHeader mHeader;
+    private QuickStatusBarHeader mHeader;
     private boolean mTriggeredExpand;
     private int mOpenX;
     private int mOpenY;
@@ -117,7 +114,7 @@
         mDetailDoneButton.setOnClickListener(doneListener);
     }
 
-    public void setQsPanel(QSPanel panel, BaseStatusBarHeader header) {
+    public void setQsPanel(QSPanel panel, QuickStatusBarHeader header) {
         mQsPanel = panel;
         mHeader = header;
         mHeader.setCallback(mQsPanelCallback);
@@ -154,7 +151,11 @@
         return mClosingDetail;
     }
 
-
+    public interface Callback {
+        void onShowingDetail(DetailAdapter detail, int x, int y);
+        void onToggleStateChanged(boolean state);
+        void onScanStateChanged(boolean state);
+    }
 
     public void handleShowingDetail(final DetailAdapter adapter, int x, int y,
             boolean toggleQs) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index d6c2447..2202b58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -11,372 +11,381 @@
  * 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.
+ * limitations under the License
  */
+
 package com.android.systemui.qs;
 
-import android.app.AlertDialog;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.text.SpannableStringBuilder;
-import android.text.method.LinkMovementMethod;
-import android.text.style.ClickableSpan;
-import android.util.Log;
-import android.view.LayoutInflater;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
+import android.os.UserManager;
+import android.provider.AlarmClock;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.OnClickListener;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
+import android.widget.Toast;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.R.dimen;
+import com.android.systemui.R.id;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
+import com.android.systemui.statusbar.phone.SettingsButton;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
+import com.android.systemui.tuner.TunerService;
 
-import static android.provider.Settings.ACTION_VPN_SETTINGS;
+public class QSFooter extends LinearLayout implements
+        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
+        SignalCallback {
+    private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
 
-public class QSFooter implements OnClickListener, DialogInterface.OnClickListener {
-    protected static final String TAG = "QSFooter";
-    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private ActivityStarter mActivityStarter;
+    private NextAlarmController mNextAlarmController;
+    private UserInfoController mUserInfoController;
+    private SettingsButton mSettingsButton;
+    protected View mSettingsContainer;
 
-    private final View mRootView;
-    private final TextView mFooterText;
-    private final ImageView mFooterIcon;
-    private final ImageView mFooterIcon2;
-    private final Context mContext;
-    private final Callback mCallback = new Callback();
-    private final SecurityController mSecurityController;
-    private final ActivityStarter mActivityStarter;
-    private final Handler mMainHandler;
+    private TextView mAlarmStatus;
+    private View mAlarmStatusCollapsed;
+    private View mDate;
 
-    private AlertDialog mDialog;
-    private QSTileHost mHost;
-    protected H mHandler;
+    private QSPanel mQsPanel;
 
-    private boolean mIsVisible;
-    private boolean mIsIconVisible;
-    private boolean mIsIcon2Visible;
-    private CharSequence mFooterTextContent = null;
-    private int mFooterTextId;
-    private int mFooterIconId;
-    private int mFooterIcon2Id;
+    private boolean mExpanded;
+    private boolean mAlarmShowing;
 
-    public QSFooter(QSPanel qsPanel, Context context) {
-        mRootView = LayoutInflater.from(context)
-                .inflate(R.layout.quick_settings_footer, qsPanel, false);
-        mRootView.setOnClickListener(this);
-        mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
-        mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
-        mFooterIcon2 = (ImageView) mRootView.findViewById(R.id.footer_icon2);
-        mFooterIconId = R.drawable.ic_qs_vpn;
-        mFooterIcon2Id = R.drawable.ic_qs_network_logging;
-        mContext = context;
-        mMainHandler = new Handler(Looper.getMainLooper());
+    protected ExpandableIndicator mExpandIndicator;
+
+    private boolean mListening;
+    private AlarmManager.AlarmClockInfo mNextAlarm;
+
+    private boolean mShowEmergencyCallsOnly;
+    protected MultiUserSwitch mMultiUserSwitch;
+    private ImageView mMultiUserAvatar;
+    private boolean mAlwaysShowMultiUserSwitch;
+
+    protected TouchAnimator mSettingsAlpha;
+    private float mExpansionAmount;
+
+    protected View mEdit;
+    private boolean mShowEditIcon;
+    private TouchAnimator mAnimator;
+    private View mDateTimeGroup;
+
+    public QSFooter(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        Resources res = getResources();
+
+        mShowEditIcon = res.getBoolean(R.bool.config_showQuickSettingsEditingIcon);
+
+        mEdit = findViewById(android.R.id.edit);
+        mEdit.setVisibility(mShowEditIcon ? VISIBLE : GONE);
+
+        if (mShowEditIcon) {
+            findViewById(android.R.id.edit).setOnClickListener(view ->
+                    Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
+                            mQsPanel.showEdit(view)));
+        }
+
+        mDateTimeGroup = findViewById(id.date_time_alarm_group);
+        mDate = findViewById(R.id.date);
+
+        mExpandIndicator = findViewById(R.id.expand_indicator);
+        mExpandIndicator.setVisibility(
+                res.getBoolean(R.bool.config_showQuickSettingsExpandIndicator)
+                        ? VISIBLE : GONE);
+
+        mSettingsButton = findViewById(R.id.settings_button);
+        mSettingsContainer = findViewById(R.id.settings_button_container);
+        mSettingsButton.setOnClickListener(this);
+
+        mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
+        mAlarmStatus = findViewById(R.id.alarm_status);
+        mDateTimeGroup.setOnClickListener(this);
+
+        mMultiUserSwitch = findViewById(R.id.multi_user_switch);
+        mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+        mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher);
+
+        // RenderThread is doing more harm than good when touching the header (to expand quick
+        // settings), so disable it for this view
+        ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
+        ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
+
+        updateResources();
+
+        mNextAlarmController = Dependency.get(NextAlarmController.class);
+        mUserInfoController = Dependency.get(UserInfoController.class);
         mActivityStarter = Dependency.get(ActivityStarter.class);
-        mSecurityController = Dependency.get(SecurityController.class);
-        mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
+        addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
+                oldBottom) -> updateAnimator(right - left));
     }
 
-    public void setHostEnvironment(QSTileHost host) {
-        mHost = host;
+    private void updateAnimator(int width) {
+        int numTiles = QuickQSPanel.getNumQuickTiles(mContext);
+        int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
+                - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
+        int remaining = (width - numTiles * size) / (numTiles - 1);
+        int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
+
+        final Builder builder = new Builder()
+                .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0)
+                .addFloat(mSettingsButton, "rotation", -120, 0)
+                .addFloat(mAlarmStatus, "alpha", 0, 1)
+                .addFloat(mAlarmStatus, "translationX", 0, -mDate.getWidth())
+                .addFloat(mAlarmStatusCollapsed, "translationX", 0, -mDate.getWidth());
+        if (mAlarmShowing) {
+            builder.addFloat(mDate, "alpha", 1, 0);
+        }
+        mAnimator = builder.build();
+        setExpansion(mExpansionAmount);
     }
 
-    public void setListening(boolean listening) {
-        if (listening) {
-            mSecurityController.addCallback(mCallback);
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateResources();
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        updateResources();
+    }
+
+    private void updateResources() {
+        FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
+
+        updateSettingsAnimator();
+    }
+
+    private void updateSettingsAnimator() {
+        mSettingsAlpha = createSettingsAlphaAnimator();
+
+        final boolean isRtl = isLayoutRtl();
+        if (isRtl && mDate.getWidth() == 0) {
+            mDate.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+                @Override
+                public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                    mDate.setPivotX(getWidth());
+                    mDate.removeOnLayoutChangeListener(this);
+                }
+            });
         } else {
-            mSecurityController.removeCallback(mCallback);
+            mDate.setPivotX(isRtl ? mDate.getWidth() : 0);
         }
     }
 
-    public void onConfigurationChanged() {
-        FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
+    @Nullable
+    private TouchAnimator createSettingsAlphaAnimator() {
+        // If the settings icon is not shown and the user switcher is always shown, then there
+        // is nothing to animate.
+        if (!mShowEditIcon && mAlwaysShowMultiUserSwitch) {
+            return null;
+        }
+
+        TouchAnimator.Builder animatorBuilder = new TouchAnimator.Builder();
+
+        if (mShowEditIcon) {
+            animatorBuilder.addFloat(mEdit, "alpha", 0, 1);
+        }
+
+        if (!mAlwaysShowMultiUserSwitch) {
+            animatorBuilder.addFloat(mMultiUserSwitch, "alpha", 0, 1);
+        }
+
+        return animatorBuilder.build();
     }
 
-    public View getView() {
-        return mRootView;
+    public void setExpanded(boolean expanded) {
+        if (mExpanded == expanded) return;
+        mExpanded = expanded;
+        updateEverything();
     }
 
-    public boolean hasFooter() {
-        return mRootView.getVisibility() != View.GONE;
+    @Override
+    public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
+        mNextAlarm = nextAlarm;
+        if (nextAlarm != null) {
+            String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
+            mAlarmStatus.setText(alarmString);
+            mAlarmStatus.setContentDescription(mContext.getString(
+                    R.string.accessibility_quick_settings_alarm, alarmString));
+            mAlarmStatusCollapsed.setContentDescription(mContext.getString(
+                    R.string.accessibility_quick_settings_alarm, alarmString));
+        }
+        if (mAlarmShowing != (nextAlarm != null)) {
+            mAlarmShowing = nextAlarm != null;
+            updateAnimator(getWidth());
+            updateEverything();
+        }
+    }
+
+    public void setExpansion(float headerExpansionFraction) {
+        mExpansionAmount = headerExpansionFraction;
+        if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
+
+        if (mSettingsAlpha != null) {
+            mSettingsAlpha.setPosition(headerExpansionFraction);
+        }
+
+        updateAlarmVisibilities();
+
+        mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
+    }
+
+    @Override
+    @VisibleForTesting
+    public void onDetachedFromWindow() {
+        setListening(false);
+        super.onDetachedFromWindow();
+    }
+
+    private void updateAlarmVisibilities() {
+        mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+        mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    public void setListening(boolean listening) {
+        if (listening == mListening) {
+            return;
+        }
+        mListening = listening;
+        updateListeners();
+    }
+
+    public View getExpandView() {
+        return findViewById(R.id.expand_indicator);
+    }
+
+    public void updateEverything() {
+        post(() -> {
+            updateVisibilities();
+            setClickable(false);
+        });
+    }
+
+    private void updateVisibilities() {
+        updateAlarmVisibilities();
+        mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
+                TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
+        final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
+
+        mMultiUserSwitch.setVisibility((mExpanded || mAlwaysShowMultiUserSwitch)
+                && mMultiUserSwitch.hasMultipleUsers() && !isDemo
+                ? View.VISIBLE : View.INVISIBLE);
+
+        if (mShowEditIcon) {
+            mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+        }
+    }
+
+    private void updateListeners() {
+        if (mListening) {
+            mNextAlarmController.addCallback(this);
+            mUserInfoController.addCallback(this);
+            if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
+                Dependency.get(NetworkController.class).addEmergencyListener(this);
+                Dependency.get(NetworkController.class).addCallback(this);
+            }
+        } else {
+            mNextAlarmController.removeCallback(this);
+            mUserInfoController.removeCallback(this);
+            Dependency.get(NetworkController.class).removeEmergencyListener(this);
+            Dependency.get(NetworkController.class).removeCallback(this);
+        }
+    }
+
+    public void setQSPanel(final QSPanel qsPanel) {
+        mQsPanel = qsPanel;
+        if (mQsPanel != null) {
+            mMultiUserSwitch.setQsPanel(qsPanel);
+        }
     }
 
     @Override
     public void onClick(View v) {
-        mHandler.sendEmptyMessage(H.CLICK);
-    }
+        if (v == mSettingsButton) {
+            MetricsLogger.action(mContext,
+                    mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
+                            : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
+            if (mSettingsButton.isTunerClick()) {
+                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+                    if (TunerService.isTunerEnabled(mContext)) {
+                        TunerService.showResetRequest(mContext, () -> {
+                            // Relaunch settings so that the tuner disappears.
+                            startSettingsActivity();
+                        });
+                    } else {
+                        Toast.makeText(getContext(), R.string.tuner_toast,
+                                Toast.LENGTH_LONG).show();
+                        TunerService.setTunerEnabled(mContext, true);
+                    }
+                    startSettingsActivity();
 
-    private void handleClick() {
-        showDeviceMonitoringDialog();
-    }
-
-    public void showDeviceMonitoringDialog() {
-        mHost.collapsePanels();
-        // TODO: Delay dialog creation until after panels are collapsed.
-        createDialog();
-    }
-
-    public void refreshState() {
-        mHandler.sendEmptyMessage(H.REFRESH_STATE);
-    }
-
-    private void handleRefreshState() {
-        boolean isVpnEnabled = mSecurityController.isVpnEnabled();
-        boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
-        mIsIconVisible = isVpnEnabled || isNetworkLoggingEnabled;
-        mIsIcon2Visible = isVpnEnabled && isNetworkLoggingEnabled;
-        if (mSecurityController.isDeviceManaged()) {
-            final CharSequence organizationName =
-                    mSecurityController.getDeviceOwnerOrganizationName();
-            if (organizationName != null) {
-                mFooterTextContent = mContext.getResources().getString(
-                        R.string.do_disclosure_with_name, organizationName);
+                });
             } else {
-                mFooterTextContent =
-                        mContext.getResources().getString(R.string.do_disclosure_generic);
+                startSettingsActivity();
             }
-            mIsVisible = true;
-            int footerIconId = isVpnEnabled
-                    ? R.drawable.ic_qs_vpn
-                    : R.drawable.ic_qs_network_logging;
-            if (mFooterIconId != footerIconId) {
-                mFooterIconId = footerIconId;
-                mMainHandler.post(mUpdateIcon);
+        } else if (v == mDateTimeGroup) {
+            if (mNextAlarm != null) {
+                PendingIntent showIntent = mNextAlarm.getShowIntent();
+                mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
+            } else {
+                mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                        AlarmClock.ACTION_SHOW_ALARMS), 0);
             }
-        } else {
-            boolean isBranded = mSecurityController.isVpnBranded();
-            mFooterTextContent = mContext.getResources().getText(
-                    isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer);
-            // Update the VPN footer icon, if needed.
-            int footerIconId = isVpnEnabled
-                    ? (isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn)
-                    : R.drawable.ic_qs_network_logging;
-            if (mFooterIconId != footerIconId) {
-                mFooterIconId = footerIconId;
-                mMainHandler.post(mUpdateIcon);
-            }
-            mIsVisible = mIsIconVisible;
         }
-        mMainHandler.post(mUpdateDisplayState);
+    }
+
+    private void startSettingsActivity() {
+        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
+                true /* dismissShade */);
     }
 
     @Override
-    public void onClick(DialogInterface dialog, int which) {
-        if (which == DialogInterface.BUTTON_NEGATIVE) {
-            final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
-            mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
-        }
-    }
-
-    private void createDialog() {
-        final String deviceOwnerPackage = mSecurityController.getDeviceOwnerName();
-        final String profileOwnerPackage = mSecurityController.getProfileOwnerName();
-        final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
-        final String primaryVpn = mSecurityController.getPrimaryVpnName();
-        final String profileVpn = mSecurityController.getProfileVpnName();
-        final CharSequence deviceOwnerOrganization =
-                mSecurityController.getDeviceOwnerOrganizationName();
-        boolean hasProfileOwner = mSecurityController.hasProfileOwner();
-        boolean isBranded = deviceOwnerPackage == null && mSecurityController.isVpnBranded();
-
-        mDialog = new SystemUIDialog(mContext);
-        if (!isBranded) {
-            mDialog.setTitle(getTitle(deviceOwnerPackage));
-        }
-        CharSequence msg = getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn,
-                profileVpn, deviceOwnerOrganization, hasProfileOwner, isBranded);
-        if (deviceOwnerPackage == null) {
-            mDialog.setMessage(msg);
-            if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
-                mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
-            }
-        } else {
-            View dialogView = LayoutInflater.from(mContext)
-                   .inflate(R.layout.quick_settings_footer_dialog, null, false);
-            mDialog.setView(dialogView);
-            TextView deviceOwnerWarning =
-                    (TextView) dialogView.findViewById(R.id.device_owner_warning);
-            deviceOwnerWarning.setText(msg);
-            // Make the link "learn more" clickable.
-            deviceOwnerWarning.setMovementMethod(new LinkMovementMethod());
-            if (primaryVpn == null) {
-                dialogView.findViewById(R.id.vpn_icon).setVisibility(View.GONE);
-                dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
-                dialogView.findViewById(R.id.vpn_warning).setVisibility(View.GONE);
-            } else {
-                final SpannableStringBuilder message = new SpannableStringBuilder();
-                message.append(mContext.getString(R.string.monitoring_description_do_body_vpn,
-                        primaryVpn));
-                if (!mSecurityController.isVpnRestricted()) {
-                    message.append(mContext.getString(
-                            R.string.monitoring_description_vpn_settings_separator));
-                    message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
-                            new VpnSpan(), 0);
-                }
-
-                TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning);
-                vpnWarning.setText(message);
-                // Make the link "Open VPN Settings" clickable.
-                vpnWarning.setMovementMethod(new LinkMovementMethod());
-            }
-            if (!isNetworkLoggingEnabled) {
-                dialogView.findViewById(R.id.network_logging_icon).setVisibility(View.GONE);
-                dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
-                dialogView.findViewById(R.id.network_logging_warning).setVisibility(View.GONE);
-            }
-        }
-
-        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
-        mDialog.show();
-        mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-    }
-
-    private String getSettingsButton() {
-        return mContext.getString(R.string.status_bar_settings_settings_button);
-    }
-
-    private String getPositiveButton(boolean isBranded) {
-        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
-    }
-
-    protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage,
-            String primaryVpn, String profileVpn, CharSequence deviceOwnerOrganization,
-            boolean hasProfileOwner, boolean isBranded) {
-        if (deviceOwnerPackage != null) {
-            final SpannableStringBuilder message = new SpannableStringBuilder();
-            if (deviceOwnerOrganization != null) {
-                message.append(mContext.getString(
-                        R.string.monitoring_description_do_header_with_name,
-                        deviceOwnerOrganization, deviceOwnerPackage));
-            } else {
-                message.append(mContext.getString(R.string.monitoring_description_do_header_generic,
-                        deviceOwnerPackage));
-            }
-            message.append("\n\n");
-            message.append(mContext.getString(R.string.monitoring_description_do_body));
-            message.append(mContext.getString(
-                    R.string.monitoring_description_do_learn_more_separator));
-            message.append(mContext.getString(R.string.monitoring_description_do_learn_more),
-                    new EnterprisePrivacySpan(), 0);
-            return message;
-        } else if (primaryVpn != null) {
-            if (profileVpn != null) {
-                return mContext.getString(R.string.monitoring_description_app_personal_work,
-                        profileOwnerPackage, profileVpn, primaryVpn);
-            } else {
-                if (isBranded) {
-                    return mContext.getString(R.string.branded_monitoring_description_app_personal,
-                            primaryVpn);
-                } else {
-                    return mContext.getString(R.string.monitoring_description_app_personal,
-                            primaryVpn);
-                }
-            }
-        } else if (profileVpn != null) {
-            return mContext.getString(R.string.monitoring_description_app_work,
-                    profileOwnerPackage, profileVpn);
-        } else if (profileOwnerPackage != null && hasProfileOwner) {
-            return mContext.getString(R.string.do_disclosure_with_name,
-                    profileOwnerPackage);
-        } else {
-            // No device owner, no personal VPN, no work VPN, no user owner. Why are we here?
-            return null;
-        }
-    }
-
-    private int getTitle(String deviceOwner) {
-        if (deviceOwner != null) {
-            return R.string.monitoring_title_device_owned;
-        } else {
-            return R.string.monitoring_title;
-        }
-    }
-
-    private final Runnable mUpdateIcon = new Runnable() {
-        @Override
-        public void run() {
-            mFooterIcon.setImageResource(mFooterIconId);
-            mFooterIcon2.setImageResource(mFooterIcon2Id);
-        }
-    };
-
-    private final Runnable mUpdateDisplayState = new Runnable() {
-        @Override
-        public void run() {
-            if (mFooterTextContent != null) {
-                mFooterText.setText(mFooterTextContent);
-            }
-            mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
-            mFooterIcon.setVisibility(mIsIconVisible ? View.VISIBLE : View.INVISIBLE);
-            mFooterIcon2.setVisibility(mIsIcon2Visible ? View.VISIBLE : View.INVISIBLE);
-        }
-    };
-
-    private class Callback implements SecurityController.SecurityControllerCallback {
-        @Override
-        public void onStateChanged() {
-            refreshState();
-        }
-    }
-
-    private class H extends Handler {
-        private static final int CLICK = 0;
-        private static final int REFRESH_STATE = 1;
-
-        private H(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            String name = null;
-            try {
-                if (msg.what == REFRESH_STATE) {
-                    name = "handleRefreshState";
-                    handleRefreshState();
-                } else if (msg.what == CLICK) {
-                    name = "handleClick";
-                    handleClick();
-                }
-            } catch (Throwable t) {
-                final String error = "Error in " + name;
-                Log.w(TAG, error, t);
-                mHost.warn(error, t);
+    public void setEmergencyCallsOnly(boolean show) {
+        boolean changed = show != mShowEmergencyCallsOnly;
+        if (changed) {
+            mShowEmergencyCallsOnly = show;
+            if (mExpanded) {
+                updateEverything();
             }
         }
     }
 
-    protected class EnterprisePrivacySpan extends ClickableSpan {
-        @Override
-        public void onClick(View widget) {
-            final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            mDialog.dismiss();
-            mContext.startActivity(intent);
-        }
-
-        @Override
-        public boolean equals(Object object) {
-            return object instanceof EnterprisePrivacySpan;
-        }
-    }
-
-    protected class VpnSpan extends ClickableSpan {
-        @Override
-        public void onClick(View widget) {
-            final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            mDialog.dismiss();
-            mContext.startActivity(intent);
-        }
+    @Override
+    public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+        mMultiUserAvatar.setImageDrawable(picture);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 95e0301..3a93d51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout.LayoutParams;
@@ -33,8 +34,6 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 public class QSFragment extends Fragment implements QS {
@@ -58,6 +57,7 @@
     private boolean mListening;
     private QSContainerImpl mContainer;
     private int mLayoutDirection;
+    private QSFooter mFooter;
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -68,9 +68,10 @@
     @Override
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        mQSPanel = (QSPanel) view.findViewById(R.id.quick_settings_panel);
-        mQSDetail = (QSDetail) view.findViewById(R.id.qs_detail);
-        mHeader = (QuickStatusBarHeader) view.findViewById(R.id.header);
+        mQSPanel = view.findViewById(R.id.quick_settings_panel);
+        mQSDetail = view.findViewById(R.id.qs_detail);
+        mHeader = view.findViewById(R.id.header);
+        mFooter = view.findViewById(R.id.qs_footer);
         mContainer = (QSContainerImpl) view;
 
         mQSDetail.setQsPanel(mQSPanel, mHeader);
@@ -79,13 +80,18 @@
         // the row to the full QS panel.
         if (getResources().getBoolean(R.bool.config_showQuickSettingsRow)) {
             mQSAnimator = new QSAnimator(this,
-                    (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
+                    mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
         }
 
-        mQSCustomizer = (QSCustomizer) view.findViewById(R.id.qs_customize);
+        mQSCustomizer = view.findViewById(R.id.qs_customize);
         mQSCustomizer.setQs(this);
     }
 
+    @Override
+    public View getHeader() {
+        return mHeader;
+    }
+
     public void setPanelView(HeightListener panelView) {
         mPanelView = panelView;
     }
@@ -116,6 +122,7 @@
     public void setHost(QSTileHost qsh) {
         mQSPanel.setHost(qsh, mQSCustomizer);
         mHeader.setQSPanel(mQSPanel);
+        mFooter.setQSPanel(mQSPanel);
         mQSDetail.setHost(qsh);
 
         if (mQSAnimator != null) {
@@ -133,13 +140,14 @@
                 : View.INVISIBLE);
         mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
                 || (mQsExpanded && !mStackScrollerOverscrolling));
+        mFooter.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                ? View.VISIBLE
+                : View.INVISIBLE);
+        mFooter.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+                || (mQsExpanded && !mStackScrollerOverscrolling));
         mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
     }
 
-    public BaseStatusBarHeader getHeader() {
-        return mHeader;
-    }
-
     public QSPanel getQsPanel() {
         return mQSPanel;
     }
@@ -155,6 +163,7 @@
     public void setHeaderClickable(boolean clickable) {
         if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
         mHeader.setClickable(clickable);
+        mFooter.setClickable(clickable);
     }
 
     public void setExpanded(boolean expanded) {
@@ -185,11 +194,13 @@
         if (DEBUG) Log.d(TAG, "setListening " + listening);
         mListening = listening;
         mHeader.setListening(listening);
+        mFooter.setListening(listening);
         mQSPanel.setListening(mListening && mQsExpanded);
     }
 
     public void setHeaderListening(boolean listening) {
         mHeader.setListening(listening);
+        mFooter.setListening(listening);
     }
 
     public void setQsExpansion(float expansion, float headerTranslation) {
@@ -201,7 +212,9 @@
                     : headerTranslation);
         }
         mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
-        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+        mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
+        int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom();
+        mQSPanel.setTranslationY(translationScaleY * heightDiff);
         mQSDetail.setFullyExpanded(expansion == 1);
 
         if (mQSAnimator != null) {
@@ -209,7 +222,7 @@
         }
 
         // Set bounds on the QS panel so it doesn't run over the header.
-        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+        mQsBounds.top = (int) (mHeader.getBottom() * (1 - expansion));
         mQsBounds.right = mQSPanel.getWidth();
         mQsBounds.bottom = mQSPanel.getHeight();
         mQSPanel.setClipBounds(mQsBounds);
@@ -245,6 +258,11 @@
     }
 
     @Override
+    public void setExpandClickListener(OnClickListener onClickListener) {
+        mFooter.getExpandView().setOnClickListener(onClickListener);
+    }
+
+    @Override
     public void closeDetail() {
         mQSPanel.closeDetail();
     }
@@ -254,6 +272,7 @@
         mContainer.updateBottom();
         mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
         mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
         // Let the panel know the position changed and it needs to update where notifications
         // and whatnot are.
         mPanelView.onQsHeightChanged();
@@ -268,7 +287,8 @@
             return getView().getHeight();
         }
         if (mQSDetail.isClosingDetail()) {
-            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+            LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
+            int panelHeight = layoutParams.topMargin + layoutParams.bottomMargin +
                     + mQSPanel.getMeasuredHeight();
             return panelHeight + getView().getPaddingBottom();
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index b257ca9..8298cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
+import android.service.quicksettings.Tile;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -31,8 +34,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.QSHost.Callback;
@@ -40,7 +42,6 @@
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.settings.BrightnessController;
 import com.android.systemui.settings.ToggleSliderView;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -64,11 +65,11 @@
     protected boolean mExpanded;
     protected boolean mListening;
 
-    private QS.Callback mCallback;
+    private QSDetail.Callback mCallback;
     private BrightnessController mBrightnessController;
     protected QSTileHost mHost;
 
-    protected QSFooter mFooter;
+    protected QSSecurityFooter mFooter;
     private boolean mGridContentVisible = true;
 
     protected QSTileLayout mTileLayout;
@@ -77,6 +78,7 @@
     private Record mDetailRecord;
 
     private BrightnessMirrorController mBrightnessMirrorController;
+    private View mDivider;
 
     public QSPanel(Context context) {
         this(context, null);
@@ -94,7 +96,7 @@
 
         setupTileLayout();
 
-        mFooter = new QSFooter(this, context);
+        mFooter = new QSSecurityFooter(this, context);
         addView(mFooter.getView());
 
         mPageIndicator = LayoutInflater.from(context).inflate(
@@ -104,11 +106,23 @@
             ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
         }
 
+        addDivider();
+
         updateResources();
 
         mBrightnessController = new BrightnessController(getContext(),
-                (ImageView) findViewById(R.id.brightness_icon),
-                (ToggleSliderView) findViewById(R.id.brightness_slider));
+                findViewById(R.id.brightness_icon),
+                findViewById(R.id.brightness_slider));
+    }
+
+    protected void addDivider() {
+        mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
+        mDivider.setBackgroundColor(getColorForState(mContext, Tile.STATE_INACTIVE));
+        addView(mDivider);
+    }
+
+    public View getDivider() {
+        return mDivider;
     }
 
     public View getPageIndicator() {
@@ -176,8 +190,8 @@
 
     public void setBrightnessMirror(BrightnessMirrorController c) {
         mBrightnessMirrorController = c;
-        ToggleSliderView brightnessSlider = (ToggleSliderView) findViewById(R.id.brightness_slider);
-        ToggleSliderView mirror = (ToggleSliderView) c.getMirror().findViewById(
+        ToggleSliderView brightnessSlider = findViewById(R.id.brightness_slider);
+        ToggleSliderView mirror = c.getMirror().findViewById(
                 R.id.brightness_slider);
         brightnessSlider.setMirror(mirror);
         brightnessSlider.setMirrorController(c);
@@ -187,7 +201,7 @@
         return mBrightnessView;
     }
 
-    public void setCallback(QS.Callback callback) {
+    public void setCallback(QSDetail.Callback callback) {
         mCallback = callback;
     }
 
@@ -515,7 +529,7 @@
         return null;
     }
 
-    public QSFooter getFooter() {
+    public QSSecurityFooter getFooter() {
         return mFooter;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
new file mode 100644
index 0000000..4b2c20f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -0,0 +1,381 @@
+/*
+ * 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.qs;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.text.SpannableStringBuilder;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.SecurityController;
+
+import static android.provider.Settings.ACTION_VPN_SETTINGS;
+
+public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener {
+    protected static final String TAG = "QSSecurityFooter";
+    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final View mRootView;
+    private final TextView mFooterText;
+    private final ImageView mFooterIcon;
+    private final ImageView mFooterIcon2;
+    private final Context mContext;
+    private final Callback mCallback = new Callback();
+    private final SecurityController mSecurityController;
+    private final ActivityStarter mActivityStarter;
+    private final Handler mMainHandler;
+
+    private AlertDialog mDialog;
+    private QSTileHost mHost;
+    protected H mHandler;
+
+    private boolean mIsVisible;
+    private boolean mIsIconVisible;
+    private boolean mIsIcon2Visible;
+    private CharSequence mFooterTextContent = null;
+    private int mFooterTextId;
+    private int mFooterIconId;
+    private int mFooterIcon2Id;
+
+    public QSSecurityFooter(QSPanel qsPanel, Context context) {
+        mRootView = LayoutInflater.from(context)
+                .inflate(R.layout.quick_settings_footer, qsPanel, false);
+        mRootView.setOnClickListener(this);
+        mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
+        mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
+        mFooterIcon2 = (ImageView) mRootView.findViewById(R.id.footer_icon2);
+        mFooterIconId = R.drawable.ic_qs_vpn;
+        mFooterIcon2Id = R.drawable.ic_qs_network_logging;
+        mContext = context;
+        mMainHandler = new Handler(Looper.getMainLooper());
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mSecurityController = Dependency.get(SecurityController.class);
+        mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
+    }
+
+    public void setHostEnvironment(QSTileHost host) {
+        mHost = host;
+    }
+
+    public void setListening(boolean listening) {
+        if (listening) {
+            mSecurityController.addCallback(mCallback);
+        } else {
+            mSecurityController.removeCallback(mCallback);
+        }
+    }
+
+    public void onConfigurationChanged() {
+        FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
+    }
+
+    public View getView() {
+        return mRootView;
+    }
+
+    public boolean hasFooter() {
+        return mRootView.getVisibility() != View.GONE;
+    }
+
+    @Override
+    public void onClick(View v) {
+        mHandler.sendEmptyMessage(H.CLICK);
+    }
+
+    private void handleClick() {
+        showDeviceMonitoringDialog();
+    }
+
+    public void showDeviceMonitoringDialog() {
+        mHost.collapsePanels();
+        // TODO: Delay dialog creation until after panels are collapsed.
+        createDialog();
+    }
+
+    public void refreshState() {
+        mHandler.sendEmptyMessage(H.REFRESH_STATE);
+    }
+
+    private void handleRefreshState() {
+        boolean isVpnEnabled = mSecurityController.isVpnEnabled();
+        boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
+        mIsIconVisible = isVpnEnabled || isNetworkLoggingEnabled;
+        mIsIcon2Visible = isVpnEnabled && isNetworkLoggingEnabled;
+        if (mSecurityController.isDeviceManaged()) {
+            final CharSequence organizationName =
+                    mSecurityController.getDeviceOwnerOrganizationName();
+            if (organizationName != null) {
+                mFooterTextContent = mContext.getResources().getString(
+                        R.string.do_disclosure_with_name, organizationName);
+            } else {
+                mFooterTextContent =
+                        mContext.getResources().getString(R.string.do_disclosure_generic);
+            }
+            mIsVisible = true;
+            int footerIconId = isVpnEnabled
+                    ? R.drawable.ic_qs_vpn
+                    : R.drawable.ic_qs_network_logging;
+            if (mFooterIconId != footerIconId) {
+                mFooterIconId = footerIconId;
+                mMainHandler.post(mUpdateIcon);
+            }
+        } else {
+            boolean isBranded = mSecurityController.isVpnBranded();
+            mFooterTextContent = mContext.getResources().getText(
+                    isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer);
+            // Update the VPN footer icon, if needed.
+            int footerIconId = isVpnEnabled
+                    ? (isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn)
+                    : R.drawable.ic_qs_network_logging;
+            if (mFooterIconId != footerIconId) {
+                mFooterIconId = footerIconId;
+                mMainHandler.post(mUpdateIcon);
+            }
+            mIsVisible = mIsIconVisible;
+        }
+        mMainHandler.post(mUpdateDisplayState);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == DialogInterface.BUTTON_NEGATIVE) {
+            final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
+            mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
+        }
+    }
+
+    private void createDialog() {
+        final String deviceOwnerPackage = mSecurityController.getDeviceOwnerName();
+        final String profileOwnerPackage = mSecurityController.getProfileOwnerName();
+        final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
+        final String primaryVpn = mSecurityController.getPrimaryVpnName();
+        final String profileVpn = mSecurityController.getProfileVpnName();
+        final CharSequence deviceOwnerOrganization =
+                mSecurityController.getDeviceOwnerOrganizationName();
+        boolean hasProfileOwner = mSecurityController.hasProfileOwner();
+        boolean isBranded = deviceOwnerPackage == null && mSecurityController.isVpnBranded();
+
+        mDialog = new SystemUIDialog(mContext);
+        if (!isBranded) {
+            mDialog.setTitle(getTitle(deviceOwnerPackage));
+        }
+        CharSequence msg = getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn,
+                profileVpn, deviceOwnerOrganization, hasProfileOwner, isBranded);
+        if (deviceOwnerPackage == null) {
+            mDialog.setMessage(msg);
+            if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
+                mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
+            }
+        } else {
+            View dialogView = LayoutInflater.from(mContext)
+                   .inflate(R.layout.quick_settings_footer_dialog, null, false);
+            mDialog.setView(dialogView);
+            TextView deviceOwnerWarning =
+                    (TextView) dialogView.findViewById(R.id.device_owner_warning);
+            deviceOwnerWarning.setText(msg);
+            // Make the link "learn more" clickable.
+            deviceOwnerWarning.setMovementMethod(new LinkMovementMethod());
+            if (primaryVpn == null) {
+                dialogView.findViewById(R.id.vpn_icon).setVisibility(View.GONE);
+                dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
+                dialogView.findViewById(R.id.vpn_warning).setVisibility(View.GONE);
+            } else {
+                final SpannableStringBuilder message = new SpannableStringBuilder();
+                message.append(mContext.getString(R.string.monitoring_description_do_body_vpn,
+                        primaryVpn));
+                if (!mSecurityController.isVpnRestricted()) {
+                    message.append(mContext.getString(
+                            R.string.monitoring_description_vpn_settings_separator));
+                    message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
+                            new VpnSpan(), 0);
+                }
+
+                TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning);
+                vpnWarning.setText(message);
+                // Make the link "Open VPN Settings" clickable.
+                vpnWarning.setMovementMethod(new LinkMovementMethod());
+            }
+            if (!isNetworkLoggingEnabled) {
+                dialogView.findViewById(R.id.network_logging_icon).setVisibility(View.GONE);
+                dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
+                dialogView.findViewById(R.id.network_logging_warning).setVisibility(View.GONE);
+            }
+        }
+
+        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
+        mDialog.show();
+        mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+
+    private String getSettingsButton() {
+        return mContext.getString(R.string.status_bar_settings_settings_button);
+    }
+
+    private String getPositiveButton(boolean isBranded) {
+        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
+    }
+
+    protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage,
+            String primaryVpn, String profileVpn, CharSequence deviceOwnerOrganization,
+            boolean hasProfileOwner, boolean isBranded) {
+        if (deviceOwnerPackage != null) {
+            final SpannableStringBuilder message = new SpannableStringBuilder();
+            if (deviceOwnerOrganization != null) {
+                message.append(mContext.getString(
+                        R.string.monitoring_description_do_header_with_name,
+                        deviceOwnerOrganization, deviceOwnerPackage));
+            } else {
+                message.append(mContext.getString(R.string.monitoring_description_do_header_generic,
+                        deviceOwnerPackage));
+            }
+            message.append("\n\n");
+            message.append(mContext.getString(R.string.monitoring_description_do_body));
+            message.append(mContext.getString(
+                    R.string.monitoring_description_do_learn_more_separator));
+            message.append(mContext.getString(R.string.monitoring_description_do_learn_more),
+                    new EnterprisePrivacySpan(), 0);
+            return message;
+        } else if (primaryVpn != null) {
+            if (profileVpn != null) {
+                return mContext.getString(R.string.monitoring_description_app_personal_work,
+                        profileOwnerPackage, profileVpn, primaryVpn);
+            } else {
+                if (isBranded) {
+                    return mContext.getString(R.string.branded_monitoring_description_app_personal,
+                            primaryVpn);
+                } else {
+                    return mContext.getString(R.string.monitoring_description_app_personal,
+                            primaryVpn);
+                }
+            }
+        } else if (profileVpn != null) {
+            return mContext.getString(R.string.monitoring_description_app_work,
+                    profileOwnerPackage, profileVpn);
+        } else if (profileOwnerPackage != null && hasProfileOwner) {
+            return mContext.getString(R.string.do_disclosure_with_name,
+                    profileOwnerPackage);
+        } else {
+            // No device owner, no personal VPN, no work VPN, no user owner. Why are we here?
+            return null;
+        }
+    }
+
+    private int getTitle(String deviceOwner) {
+        if (deviceOwner != null) {
+            return R.string.monitoring_title_device_owned;
+        } else {
+            return R.string.monitoring_title;
+        }
+    }
+
+    private final Runnable mUpdateIcon = new Runnable() {
+        @Override
+        public void run() {
+            mFooterIcon.setImageResource(mFooterIconId);
+            mFooterIcon2.setImageResource(mFooterIcon2Id);
+        }
+    };
+
+    private final Runnable mUpdateDisplayState = new Runnable() {
+        @Override
+        public void run() {
+            if (mFooterTextContent != null) {
+                mFooterText.setText(mFooterTextContent);
+            }
+            mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
+            mFooterIcon.setVisibility(mIsIconVisible ? View.VISIBLE : View.INVISIBLE);
+            mFooterIcon2.setVisibility(mIsIcon2Visible ? View.VISIBLE : View.INVISIBLE);
+        }
+    };
+
+    private class Callback implements SecurityController.SecurityControllerCallback {
+        @Override
+        public void onStateChanged() {
+            refreshState();
+        }
+    }
+
+    private class H extends Handler {
+        private static final int CLICK = 0;
+        private static final int REFRESH_STATE = 1;
+
+        private H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            String name = null;
+            try {
+                if (msg.what == REFRESH_STATE) {
+                    name = "handleRefreshState";
+                    handleRefreshState();
+                } else if (msg.what == CLICK) {
+                    name = "handleClick";
+                    handleClick();
+                }
+            } catch (Throwable t) {
+                final String error = "Error in " + name;
+                Log.w(TAG, error, t);
+                mHost.warn(error, t);
+            }
+        }
+    }
+
+    protected class EnterprisePrivacySpan extends ClickableSpan {
+        @Override
+        public void onClick(View widget) {
+            final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            mDialog.dismiss();
+            mContext.startActivity(intent);
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            return object instanceof EnterprisePrivacySpan;
+        }
+    }
+
+    protected class VpnSpan extends ClickableSpan {
+        @Override
+        public void onClick(View widget) {
+            final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            mDialog.dismiss();
+            mContext.startActivity(intent);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
rename to packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index bd7be91..0ca115e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -1,20 +1,18 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 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
+ * 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.
+ * 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;
+package com.android.systemui.qs;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -36,30 +34,14 @@
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
-import com.android.systemui.qs.tiles.AirplaneModeTile;
-import com.android.systemui.qs.tiles.BatterySaverTile;
-import com.android.systemui.qs.tiles.BluetoothTile;
-import com.android.systemui.qs.tiles.CastTile;
-import com.android.systemui.qs.tiles.CellularTile;
-import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.DataSaverTile;
-import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.qs.tiles.FlashlightTile;
-import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.qs.tiles.IntentTile;
-import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.NfcTile;
-import com.android.systemui.qs.tiles.NightDisplayTile;
-import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.qs.tiles.UserTile;
-import com.android.systemui.qs.tiles.WifiTile;
-import com.android.systemui.qs.tiles.WorkModeTile;
+import com.android.systemui.statusbar.phone.AutoTileManager;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index c8a232f..8539cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -30,8 +30,6 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.qs.tileimpl.QSTileBaseView;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -47,7 +45,6 @@
 
     private int mMaxTiles;
     protected QSPanel mFullPanel;
-    private View mHeader;
 
     public QuickQSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -66,6 +63,10 @@
     }
 
     @Override
+    protected void addDivider() {
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
@@ -79,7 +80,6 @@
 
     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
         mFullPanel = fullPanel;
-        mHeader = header;
     }
 
     @Override
@@ -141,7 +141,7 @@
         }
     };
 
-    public int getNumQuickTiles(Context context) {
+    public static int getNumQuickTiles(Context context) {
         return Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, 6);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
new file mode 100644
index 0000000..8c1c89f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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.qs;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.support.annotation.VisibleForTesting;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSDetail.Callback;
+import com.android.systemui.statusbar.SignalClusterView;
+
+
+public class QuickStatusBarHeader extends RelativeLayout {
+
+    private ActivityStarter mActivityStarter;
+
+    private QSPanel mQsPanel;
+
+    private boolean mExpanded;
+    private boolean mListening;
+
+    protected QuickQSPanel mHeaderQsPanel;
+    protected QSTileHost mHost;
+
+    public QuickStatusBarHeader(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        Resources res = getResources();
+
+        mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
+        mHeaderQsPanel.setVisibility(res.getBoolean(R.bool.config_showQuickSettingsRow)
+                ? VISIBLE : GONE);
+
+        // RenderThread is doing more harm than good when touching the header (to expand quick
+        // settings), so disable it for this view
+
+        updateResources();
+
+        // Set the light/dark theming on the header status UI to match the current theme.
+        SignalClusterView cluster = findViewById(R.id.signal_cluster);
+        int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
+        float intensity = colorForeground == Color.WHITE ? 0 : 1;
+        cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground);
+
+        BatteryMeterView battery = findViewById(R.id.battery);
+        battery.setForceShowPercent(true);
+        int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
+        battery.setRawColors(colorForeground, colorSecondary);
+
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateResources();
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        updateResources();
+    }
+
+    private void updateResources() {
+    }
+
+    public int getCollapsedHeight() {
+        return getHeight();
+    }
+
+    public int getExpandedHeight() {
+        return getHeight();
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (mExpanded == expanded) return;
+        mExpanded = expanded;
+        mHeaderQsPanel.setExpanded(expanded);
+        updateEverything();
+    }
+
+    public void setExpansion(float headerExpansionFraction) {
+    }
+
+    @Override
+    @VisibleForTesting
+    public void onDetachedFromWindow() {
+        setListening(false);
+        super.onDetachedFromWindow();
+    }
+
+    public void setListening(boolean listening) {
+        if (listening == mListening) {
+            return;
+        }
+        mHeaderQsPanel.setListening(listening);
+        mListening = listening;
+    }
+
+    public void updateEverything() {
+        post(() -> {
+            setClickable(false);
+        });
+    }
+
+    public void setQSPanel(final QSPanel qsPanel) {
+        mQsPanel = qsPanel;
+        setupHost(qsPanel.getHost());
+    }
+
+    public void setupHost(final QSTileHost host) {
+        mHost = host;
+        //host.setHeaderView(mExpandIndicator);
+        mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
+        mHeaderQsPanel.setHost(host, null /* No customization in header */);
+    }
+
+    public void setCallback(Callback qsPanelCallback) {
+        mHeaderQsPanel.setCallback(qsPanelCallback);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index b09c090..01f8169 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -29,12 +29,12 @@
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
 
 /** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/
-public final class SignalTileView extends QSIconViewImpl {
+public class SignalTileView extends QSIconViewImpl {
     private static final long DEFAULT_DURATION = new ValueAnimator().getDuration();
     private static final long SHORT_DURATION = DEFAULT_DURATION / 3;
 
-    private FrameLayout mIconFrame;
-    private ImageView mSignal;
+    protected FrameLayout mIconFrame;
+    protected ImageView mSignal;
     private ImageView mIn;
     private ImageView mOut;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 2c45d6a..c0fb4d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -44,7 +44,7 @@
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
 
@@ -72,6 +72,8 @@
     private NotificationsQuickSettingsContainer mNotifQsContainer;
     private QS mQs;
     private boolean mFinishedFetchingTiles = false;
+    private int mX;
+    private int mY;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
@@ -134,6 +136,8 @@
 
     public void show(int x, int y) {
         if (!isShown) {
+            mX = x;
+            mY = y;
             MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = true;
             setTileSpecs();
@@ -164,7 +168,7 @@
             mToolbar.dismissPopupMenus();
             setCustomizing(false);
             save();
-            mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
+            mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
             mNotifQsContainer.setCustomizerAnimating(true);
             mNotifQsContainer.setCustomizerShowing(false);
             announceForAccessibility(mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 91bef27..c33d7da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -47,7 +47,7 @@
 import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
 import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
 import com.android.systemui.qs.external.CustomTile;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index df7cbaf..547bef7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -35,7 +35,7 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
 import com.android.systemui.qs.external.CustomTile;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -109,7 +109,7 @@
 
     private void addPackageTiles(Handler mainHandler, Handler bgHandler) {
         bgHandler.post(() -> {
-            Collection<QSTile<?>> params = mHost.getTiles();
+            Collection<QSTile> params = mHost.getTiles();
             PackageManager pm = mContext.getPackageManager();
             List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                     new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
@@ -150,8 +150,8 @@
         });
     }
 
-    private State getState(Collection<QSTile<?>> tiles, String spec) {
-        for (QSTile<?> tile : tiles) {
+    private State getState(Collection<QSTile> tiles, String spec) {
+        for (QSTile tile : tiles) {
             if (spec.equals(tile.getTileSpec())) {
                 return tile.getState().copy();
             }
@@ -165,7 +165,7 @@
         }
         TileInfo info = new TileInfo();
         info.state = state;
-        info.state.minimalAccessibilityClassName = info.state.expandedAccessibilityClassName =
+        info.state.expandedAccessibilityClassName =
                 Button.class.getName();
         info.spec = spec;
         info.appLabel = appLabel;
@@ -180,7 +180,6 @@
         state.label = label;
         state.contentDescription = label;
         state.icon = new DrawableIcon(drawable);
-        state.autoMirrorDrawable = false;
         addTile(spec, appLabel, state, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 58e5acb..6f35017 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -41,7 +41,7 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import libcore.util.Objects;
 
 import static android.view.Display.DEFAULT_DISPLAY;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index ec4ca7a6..d9c3cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -37,7 +37,7 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index a683609..17a0d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -38,7 +38,7 @@
 import com.android.systemui.qs.tiles.UserTile;
 import com.android.systemui.qs.tiles.WifiTile;
 import com.android.systemui.qs.tiles.WorkModeTile;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 
 public class QSFactoryImpl implements QSFactory {
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 3bb198f..a751ef4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.qs.QSTile.State;
 
 import java.util.Objects;
 
@@ -81,7 +82,7 @@
         setIcon((ImageView) mIcon, state);
     }
 
-    protected void setIcon(ImageView iv, QSTile.State state) {
+    protected void updateIcon(ImageView iv, State state) {
         if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
             Drawable d = state.icon != null
                     ? iv.isShown() && mAnimationEnabled ? state.icon.getDrawable(mContext)
@@ -101,13 +102,17 @@
                 }
             }
         }
+    }
+
+    protected void setIcon(ImageView iv, QSTile.State state) {
+        updateIcon(iv, state);
         if (state.disabledByPolicy) {
             iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
         } else {
             iv.clearColorFilter();
         }
         if (state.state != mState) {
-            int color = getColorForState(getContext(), state.state);
+            int color = getColor(state.state);
             mState = state.state;
             if (iv.isShown()) {
                 animateGrayScale(mTint, color, iv);
@@ -119,6 +124,10 @@
         }
     }
 
+    protected int getColor(int state) {
+        return getColorForState(getContext(), state);
+    }
+
     public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
         final float fromAlpha = Color.alpha(fromColor);
         final float toAlpha = Color.alpha(toColor);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 585b72f..5ac7891 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -34,7 +34,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index bcc553e..c7979d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -40,7 +40,7 @@
 import com.android.settingslib.graph.UsageView;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 6554087..d552a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -34,7 +34,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 68aefab..a1d3d26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -31,7 +31,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 85788f3..ca70336 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -24,7 +24,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
+import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -32,12 +32,12 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
-import com.android.systemui.qs.QSHost;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.qs.CellTileView;
+import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -83,7 +83,7 @@
 
     @Override
     public QSIconView createTileView(Context context) {
-        return new SignalTileView(context);
+        return new CellTileView(context);
     }
 
     @Override
@@ -128,32 +128,13 @@
         } else {
             state.icon = ResourceIcon.get(iconId);
         }
-        state.dualTarget = true;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
 
-        state.label = cb.enabled
-                ? removeTrailingPeriod(cb.enabledDesc)
-                : r.getString(R.string.quick_settings_rssi_emergency_only);
+        state.label = r.getString(R.string.mobile_data);
 
-        final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
-                ? cb.signalContentDescription
-                : r.getString(R.string.accessibility_no_signal);
-
-        if (cb.noSim) {
-            state.contentDescription = state.label;
-        } else {
-            String enabledDesc = cb.enabled ? r.getString(R.string.accessibility_cell_data_on)
-                    : r.getString(R.string.accessibility_cell_data_off);
-
-            state.contentDescription = r.getString(
-                    R.string.accessibility_quick_settings_mobile,
-                    enabledDesc, signalContentDesc,
-                    state.label);
-        }
-        state.contentDescription = state.contentDescription + "," + r.getString(
-                R.string.accessibility_quick_settings_open_settings, getTileLabel());
-        state.expandedAccessibilityClassName = Button.class.getName();
+        state.contentDescription = state.label;
+        state.expandedAccessibilityClassName = Switch.class.getName();
         state.value = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 5f89e23..d3586c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -40,7 +40,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index c998431..d6043f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -23,7 +23,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 1b5b64c..0270641 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -33,7 +33,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index cd9a49d..7512efa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -24,6 +24,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.Prefs.Key;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DataSaverController.Listener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 8cad85c..820638c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -32,7 +32,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -74,7 +74,7 @@
         if (mUserListener == null) {
             return false;
         }
-        return mUserListener.getCount() != 0;
+        return mUserListener.getUserCount() > 1;
     }
 
     public void setUserSwitcherController(UserSwitcherController userSwitcherController) {
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 e6d3168..c24a2a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -295,7 +295,6 @@
             lp.width = panelWidth;
             lp.gravity = panelGravity;
             mQsFrame.setLayoutParams(lp);
-            post(mUpdateHeader);
         }
 
         lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -2140,13 +2139,6 @@
         mKeyguardUserSwitcher = keyguardUserSwitcher;
     }
 
-    private final Runnable mUpdateHeader = new Runnable() {
-        @Override
-        public void run() {
-            mQs.getHeader().updateEverything();
-        }
-    };
-
     public void onScreenTurningOn() {
         mKeyguardStatusView.refreshTime();
     }
@@ -2442,7 +2434,7 @@
         public void onFragmentViewCreated(String tag, Fragment fragment) {
             mQs = (QS) fragment;
             mQs.setPanelView(NotificationPanelView.this);
-            mQs.getHeader().getExpandView().setOnClickListener(NotificationPanelView.this);
+            mQs.setExpandClickListener(NotificationPanelView.this);
             mQs.setHeaderClickable(mQsExpansionEnabled);
             mQs.setKeyguardShowing(mKeyguardShowing);
             mQs.setOverscrolling(mStackScrollerOverscrolling);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
deleted file mode 100644
index a5590f2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
-import android.os.UserManager;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.telephony.SubscriptionInfo;
-import android.util.AttributeSet;
-import android.util.SparseBooleanArray;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.KeyguardStatusView;
-import com.android.settingslib.Utils;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.BatteryMeterView;
-import com.android.systemui.Dependency;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QS.Callback;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QuickQSPanel;
-import com.android.systemui.qs.TouchAnimator;
-import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.statusbar.SignalClusterView;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import com.android.systemui.tuner.TunerService;
-
-import java.util.List;
-
-public class QuickStatusBarHeader extends BaseStatusBarHeader implements
-        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
-        SignalCallback {
-    private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
-
-    private ActivityStarter mActivityStarter;
-    private NextAlarmController mNextAlarmController;
-    private UserInfoController mUserInfoController;
-    private SettingsButton mSettingsButton;
-    protected View mSettingsContainer;
-
-    private TextView mAlarmStatus;
-    private View mAlarmStatusCollapsed;
-    private ViewGroup mDateTimeGroup;
-    private ViewGroup mDateTimeAlarmGroup;
-
-    private QSPanel mQsPanel;
-
-    private boolean mExpanded;
-    private boolean mAlarmShowing;
-
-    private TextView mEmergencyOnly;
-
-    protected ExpandableIndicator mExpandIndicator;
-
-    private boolean mListening;
-    private AlarmManager.AlarmClockInfo mNextAlarm;
-
-    protected QuickQSPanel mHeaderQsPanel;
-    private boolean mShowEmergencyCallsOnly;
-    protected MultiUserSwitch mMultiUserSwitch;
-    private ImageView mMultiUserAvatar;
-    private boolean mAlwaysShowMultiUserSwitch;
-
-    private TouchAnimator mAnimator;
-    protected TouchAnimator mSettingsAlpha;
-    private float mExpansionAmount;
-    protected QSTileHost mHost;
-
-    protected View mEdit;
-    private boolean mShowEditIcon;
-
-    private boolean mShowFullAlarm;
-    private float mDateTimeTranslation;
-    private SparseBooleanArray mRoamingsBySubId = new SparseBooleanArray();
-    private boolean mIsRoaming;
-
-    public QuickStatusBarHeader(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        Resources res = getResources();
-
-        mEmergencyOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
-
-        mShowEditIcon = res.getBoolean(R.bool.config_showQuickSettingsEditingIcon);
-
-        mEdit = findViewById(android.R.id.edit);
-        mEdit.setVisibility(mShowEditIcon ? VISIBLE : GONE);
-
-        if (mShowEditIcon) {
-            findViewById(android.R.id.edit).setOnClickListener(view ->
-                    Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
-                            mQsPanel.showEdit(view)));
-        }
-
-        mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
-        mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
-        mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
-        mDateTimeGroup.setPivotX(0);
-        mDateTimeGroup.setPivotY(0);
-        mDateTimeTranslation = res.getDimension(R.dimen.qs_date_time_translation);
-        mShowFullAlarm = res.getBoolean(R.bool.quick_settings_show_full_alarm);
-
-        mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
-        mExpandIndicator.setVisibility(
-                res.getBoolean(R.bool.config_showQuickSettingsExpandIndicator)
-                ? VISIBLE : GONE);
-
-        mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
-        mHeaderQsPanel.setVisibility(res.getBoolean(R.bool.config_showQuickSettingsRow)
-                ? VISIBLE : GONE);
-
-        mSettingsButton = (SettingsButton) findViewById(R.id.settings_button);
-        mSettingsContainer = findViewById(R.id.settings_button_container);
-        mSettingsButton.setOnClickListener(this);
-
-        mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
-        mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
-        mAlarmStatus.setOnClickListener(this);
-
-        mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
-        mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
-        mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher);
-
-        // RenderThread is doing more harm than good when touching the header (to expand quick
-        // settings), so disable it for this view
-        ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
-        ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
-
-        updateResources();
-
-        // Set the light/dark theming on the header status UI to match the current theme.
-        SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster);
-        int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
-        float intensity = colorForeground == Color.WHITE ? 0 : 1;
-        cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground);
-
-        BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
-        battery.setForceShowPercent(true);
-        int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
-        battery.setRawColors(colorForeground, colorSecondary);
-
-        mNextAlarmController = Dependency.get(NextAlarmController.class);
-        mUserInfoController = Dependency.get(UserInfoController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        updateResources();
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-        updateResources();
-    }
-
-    private void updateResources() {
-        FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
-        FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
-
-        Builder builder = new Builder()
-                .addFloat(mShowFullAlarm ? mAlarmStatus : findViewById(R.id.date), "alpha", 0, 1)
-                .addFloat(mEmergencyOnly, "alpha", 0, 1);
-        if (mShowFullAlarm) {
-            builder.addFloat(mAlarmStatusCollapsed, "alpha", 1, 0);
-        }
-        mAnimator = builder.build();
-
-        updateSettingsAnimator();
-    }
-
-    private void updateSettingsAnimator() {
-        mSettingsAlpha = createSettingsAlphaAnimator();
-
-        final boolean isRtl = isLayoutRtl();
-        if (isRtl && mDateTimeGroup.getWidth() == 0) {
-            mDateTimeGroup.addOnLayoutChangeListener(new OnLayoutChangeListener() {
-                @Override
-                public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    mDateTimeGroup.setPivotX(getWidth());
-                    mDateTimeGroup.removeOnLayoutChangeListener(this);
-                }
-            });
-        } else {
-            mDateTimeGroup.setPivotX(isRtl ? mDateTimeGroup.getWidth() : 0);
-        }
-    }
-
-    @Nullable
-    private TouchAnimator createSettingsAlphaAnimator() {
-        // If the settings icon is not shown and the user switcher is always shown, then there
-        // is nothing to animate.
-        if (!mShowEditIcon && mAlwaysShowMultiUserSwitch) {
-            return null;
-        }
-
-        TouchAnimator.Builder animatorBuilder = new TouchAnimator.Builder();
-
-        if (mShowEditIcon) {
-            animatorBuilder.addFloat(mEdit, "alpha", 0, 1);
-        }
-
-        if (!mAlwaysShowMultiUserSwitch) {
-            animatorBuilder.addFloat(mMultiUserSwitch, "alpha", 0, 1);
-        }
-
-        return animatorBuilder.build();
-    }
-
-    @Override
-    public int getCollapsedHeight() {
-        return getHeight();
-    }
-
-    @Override
-    public int getExpandedHeight() {
-        return getHeight();
-    }
-
-    @Override
-    public void setExpanded(boolean expanded) {
-        if (mExpanded == expanded) return;
-        mExpanded = expanded;
-        mHeaderQsPanel.setExpanded(expanded);
-        updateEverything();
-    }
-
-    @Override
-    public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
-        mNextAlarm = nextAlarm;
-        if (nextAlarm != null) {
-            String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
-            mAlarmStatus.setText(alarmString);
-            mAlarmStatus.setContentDescription(mContext.getString(
-                    R.string.accessibility_quick_settings_alarm, alarmString));
-            mAlarmStatusCollapsed.setContentDescription(mContext.getString(
-                    R.string.accessibility_quick_settings_alarm, alarmString));
-        }
-        if (mAlarmShowing != (nextAlarm != null)) {
-            mAlarmShowing = nextAlarm != null;
-            updateEverything();
-        }
-    }
-
-    @Override
-    public void setExpansion(float headerExpansionFraction) {
-        mExpansionAmount = headerExpansionFraction;
-        updateDateTimePosition();
-        mAnimator.setPosition(headerExpansionFraction);
-
-        if (mSettingsAlpha != null) {
-            mSettingsAlpha.setPosition(headerExpansionFraction);
-        }
-
-        updateAlarmVisibilities();
-
-        mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
-    }
-
-    @Override
-    @VisibleForTesting
-    public void onDetachedFromWindow() {
-        setListening(false);
-        super.onDetachedFromWindow();
-    }
-
-    private void updateAlarmVisibilities() {
-        mAlarmStatus.setVisibility(mAlarmShowing && mShowFullAlarm ? View.VISIBLE : View.INVISIBLE);
-        mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    public void setListening(boolean listening) {
-        if (listening == mListening) {
-            return;
-        }
-        mHeaderQsPanel.setListening(listening);
-        mListening = listening;
-        updateListeners();
-    }
-
-    @Override
-    public View getExpandView() {
-        return findViewById(R.id.expand_indicator);
-    }
-
-    @Override
-    public void updateEverything() {
-        post(() -> {
-            updateVisibilities();
-            setClickable(false);
-        });
-    }
-
-    private void updateVisibilities() {
-        updateAlarmVisibilities();
-        updateDateTimePosition();
-        mEmergencyOnly.setVisibility(mExpanded && (mShowEmergencyCallsOnly || mIsRoaming)
-                ? View.VISIBLE : View.INVISIBLE);
-        mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
-                TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
-        final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
-
-        mMultiUserSwitch.setVisibility((mExpanded || mAlwaysShowMultiUserSwitch)
-                && mMultiUserSwitch.hasMultipleUsers() && !isDemo
-                ? View.VISIBLE : View.INVISIBLE);
-
-        if (mShowEditIcon) {
-            mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
-        }
-    }
-
-    private void updateDateTimePosition() {
-        mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly || mIsRoaming
-                ? mExpansionAmount * mDateTimeTranslation : 0);
-    }
-
-    private void updateListeners() {
-        if (mListening) {
-            mNextAlarmController.addCallback(this);
-            mUserInfoController.addCallback(this);
-            if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
-                Dependency.get(NetworkController.class).addEmergencyListener(this);
-                Dependency.get(NetworkController.class).addCallback(this);
-            }
-        } else {
-            mNextAlarmController.removeCallback(this);
-            mUserInfoController.removeCallback(this);
-            Dependency.get(NetworkController.class).removeEmergencyListener(this);
-            Dependency.get(NetworkController.class).removeCallback(this);
-        }
-    }
-
-    public void setQSPanel(final QSPanel qsPanel) {
-        mQsPanel = qsPanel;
-        setupHost(qsPanel.getHost());
-        if (mQsPanel != null) {
-            mMultiUserSwitch.setQsPanel(qsPanel);
-        }
-    }
-
-    public void setupHost(final QSTileHost host) {
-        mHost = host;
-        //host.setHeaderView(mExpandIndicator);
-        mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
-        mHeaderQsPanel.setHost(host, null /* No customization in header */);
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v == mSettingsButton) {
-            MetricsLogger.action(mContext,
-                    mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
-                            : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
-            if (mSettingsButton.isTunerClick()) {
-                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
-                    if (TunerService.isTunerEnabled(mContext)) {
-                        TunerService.showResetRequest(mContext, () -> {
-                            // Relaunch settings so that the tuner disappears.
-                            startSettingsActivity();
-                        });
-                    } else {
-                        Toast.makeText(getContext(), R.string.tuner_toast,
-                                Toast.LENGTH_LONG).show();
-                        TunerService.setTunerEnabled(mContext, true);
-                    }
-                    startSettingsActivity();
-
-                });
-            } else {
-                startSettingsActivity();
-            }
-        } else if (v == mAlarmStatus && mNextAlarm != null) {
-            PendingIntent showIntent = mNextAlarm.getShowIntent();
-            mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
-        }
-    }
-
-    private void startSettingsActivity() {
-        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
-                true /* dismissShade */);
-    }
-
-    @Override
-    public void setCallback(Callback qsPanelCallback) {
-        mHeaderQsPanel.setCallback(qsPanelCallback);
-    }
-
-    @Override
-    public void setEmergencyCallsOnly(boolean show) {
-        boolean changed = show != mShowEmergencyCallsOnly;
-        if (changed) {
-            mShowEmergencyCallsOnly = show;
-            if (mExpanded) {
-                updateEverything();
-            }
-        }
-    }
-
-    @Override
-    public void setSubs(List<SubscriptionInfo> subs) {
-        mRoamingsBySubId.clear();
-        updateRoaming();
-    }
-
-    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-            int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
-            String description, boolean isWide, int subId, boolean roaming) {
-        mRoamingsBySubId.put(subId, roaming);
-        updateRoaming();
-    }
-
-    private void updateRoaming() {
-        boolean isRoaming = calculateRoaming();
-        if (mIsRoaming != isRoaming) {
-            mIsRoaming = isRoaming;
-            mEmergencyOnly.setText(mIsRoaming ? R.string.accessibility_data_connection_roaming
-                    : com.android.internal.R.string.emergency_calls_only);
-            if (mExpanded) {
-                updateEverything();
-            }
-        }
-    }
-
-    private boolean calculateRoaming() {
-        for (int i = 0; i < mRoamingsBySubId.size(); i++) {
-            if (mRoamingsBySubId.valueAt(i)) return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
-        mMultiUserAvatar.setImageDrawable(picture);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 816a39d..19be586 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -140,11 +140,11 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
@@ -204,10 +204,8 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -436,7 +434,6 @@
     private QSPanel mQSPanel;
 
     // top bar
-    BaseStatusBarHeader mHeader;
     protected KeyguardStatusBarView mKeyguardStatusBar;
     KeyguardStatusView mKeyguardStatusView;
     KeyguardBottomAreaView mKeyguardBottomArea;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index bb0748c..f0af77d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -81,6 +81,7 @@
     private static final int AM_PM_STYLE_GONE    = 2;
 
     private final int mAmPmStyle;
+    private final boolean mShowDark;
     private boolean mShowSeconds;
     private Handler mSecondsHandler;
 
@@ -100,6 +101,7 @@
                 0, 0);
         try {
             mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
+            mShowDark = a.getBoolean(R.styleable.Clock_showDark, true);
         } finally {
             a.recycle();
         }
@@ -124,7 +126,9 @@
             Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
                     StatusBarIconController.ICON_BLACKLIST);
             SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
-            Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
+            if (mShowDark) {
+                Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
+            }
         }
 
         // NOTE: It's safe to do these after registering the receiver since the receiver always runs
@@ -147,7 +151,9 @@
             Dependency.get(TunerService.class).removeTunable(this);
             SysUiServiceProvider.getComponent(getContext(), CommandQueue.class)
                     .removeCallbacks(this);
-            Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
+            if (mShowDark) {
+                Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index a776e99..53671a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -57,7 +57,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUISecondaryUserService;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -664,6 +664,27 @@
             controller.addAdapter(new WeakReference<>(this));
         }
 
+        public int getUserCount() {
+            boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
+                    && mKeyguardMonitor.isSecure()
+                    && !mKeyguardMonitor.canSkipBouncer();
+            if (!secureKeyguardShowing) {
+                return mController.getUsers().size();
+            }
+            // The lock screen is secure and showing. Filter out restricted records.
+            final int N = mController.getUsers().size();
+            int count = 0;
+            for (int i = 0; i < N; i++) {
+                if (mController.getUsers().get(i).isGuest) continue;
+                if (mController.getUsers().get(i).isRestricted) {
+                    break;
+                } else {
+                    count++;
+                }
+            }
+            return count;
+        }
+
         @Override
         public int getCount() {
             boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java
index 0d87d6b..9849800 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java
@@ -21,8 +21,7 @@
 import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
 import com.android.systemui.plugins.annotations.Requires;
 import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.qs.QS.Callback;
-import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QS.HeightListener;
 
 import org.junit.Rule;
@@ -95,7 +94,6 @@
     }
 
     @Requires(target = QS.class, version = QS.VERSION)
-    @Requires(target = Callback.class, version = Callback.VERSION)
     @Requires(target = HeightListener.class, version = HeightListener.VERSION)
     @Requires(target = DetailAdapter.class, version = DetailAdapter.VERSION)
     public static class QSImpl {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index e7fa799..7153340 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -19,15 +19,13 @@
 
 import android.os.Looper;
 
+import com.android.keyguard.CarrierText;
 import com.android.systemui.Dependency;
 import com.android.systemui.FragmentTestCase;
 import com.android.systemui.R;
 import com.android.systemui.SysUIRunner;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.LayoutInflaterBuilder;
 import com.android.systemui.utils.TestableLooper;
 import com.android.systemui.utils.TestableLooper.RunWithLooper;
@@ -37,9 +35,6 @@
 import org.junit.runner.RunWith;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -58,6 +53,7 @@
                         .replace("com.android.systemui.statusbar.policy.SplitClockView",
                                 FrameLayout.class)
                         .replace("TextClock", View.class)
+                        .replace(CarrierText.class, View.class)
                         .build());
 
         injectTestDependency(Dependency.BG_LOOPER, TestableLooper.get(this).getLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 2f6487b..e38c30f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -42,7 +42,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class QSFooterTest extends SysuiTestCase {
+public class QSSecurityFooterTest extends SysuiTestCase {
 
     private final String MANAGING_ORGANIZATION = "organization";
     private final String DEVICE_OWNER_PACKAGE = "TestDPC";
@@ -52,7 +52,7 @@
     private TextView mFooterText;
     private TestableImageView mFooterIcon;
     private TestableImageView mFooterIcon2;
-    private QSFooter mFooter;
+    private QSSecurityFooter mFooter;
     private SecurityController mSecurityController = mock(SecurityController.class);
 
     @Before
@@ -64,7 +64,7 @@
                         .replace("ImageView", TestableImageView.class)
                         .build());
         Handler h = new Handler(Looper.getMainLooper());
-        h.post(() -> mFooter = new QSFooter(null, mContext));
+        h.post(() -> mFooter = new QSSecurityFooter(null, mContext));
         waitForIdleSync(h);
         mRootView = (ViewGroup) mFooter.getView();
         mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 308c779..11491a75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -34,7 +34,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.tileimpl.QSTileView;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -59,7 +60,7 @@
     private QSPanel.TileRecord createTileRecord() {
         QSPanel.TileRecord tileRecord = new QSPanel.TileRecord();
         tileRecord.tile = mock(QSTile.class);
-        tileRecord.tileView = spy(new QSTileView(mContext, new QSIconView(mContext)));
+        tileRecord.tileView = spy(new QSTileView(mContext, new QSIconViewImpl(mContext)));
         return tileRecord;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index b983820..d1e17f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -15,29 +15,27 @@
 package com.android.systemui.qs.customize;
 
 import static junit.framework.Assert.assertEquals;
-
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.os.Message;
-import android.test.suitebuilder.annotation.SmallTest;
-
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUIRunner;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.phone.QSTileHost;
-
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.utils.TestableLooper;
-import com.android.systemui.utils.TestableLooper.MessageHandler;
 import com.android.systemui.utils.TestableLooper.RunWithLooper;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
 @SmallTest
 @RunWith(SysUIRunner.class)
 @RunWithLooper
@@ -65,7 +63,7 @@
     public void testCompletionCalledAfterTilesFetched() {
         QSTile mockTile = mock(QSTile.class);
         State mockState = mock(State.class);
-        when(mockTile.newTileState()).thenReturn(mockState);
+        when(mockState.copy()).thenReturn(mockState);
         when(mockTile.getState()).thenReturn(mockState);
         when(mockTile.isAvailable()).thenReturn(true);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 70c7d3e..6d7b50f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -27,7 +27,7 @@
 
 import com.android.systemui.SysUIRunner;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.utils.TestableLooper;
 import com.android.systemui.utils.TestableLooper.RunWithLooper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 9a477d2..3ccb160 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -24,6 +24,7 @@
 import com.android.systemui.Prefs.Key;
 import com.android.systemui.SysUIRunner;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.QSTileHost;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
deleted file mode 100644
index 99cecff..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.R.layout;
-import com.android.systemui.SysUIRunner;
-import com.android.systemui.utils.TestableLooper;
-import com.android.systemui.utils.TestableLooper.RunWithLooper;
-import com.android.systemui.utils.ViewUtils;
-import com.android.systemui.utils.leaks.LeakCheckedTest;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-
-@RunWith(SysUIRunner.class)
-@RunWithLooper(setAsMainLooper = true)
-public class QuickStatusBarHeaderTest extends LeakCheckedTest {
-
-    @Before
-    public void setup() throws NoSuchFieldException, IllegalAccessException {
-        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
-    }
-
-    @Test
-    @Ignore("Flaky")
-    public void testRoamingStuck() throws Exception {
-        TestableLooper looper = TestableLooper.get(this);
-        assertEquals(Looper.myLooper(), looper.getLooper());
-        assertEquals(Looper.myLooper(), Looper.getMainLooper());
-        QuickStatusBarHeader header = (QuickStatusBarHeader) LayoutInflater.from(mContext).inflate(
-                layout.quick_status_bar_expanded_header, null);
-        header.setExpanded(true);
-
-        ViewUtils.attachView(header);
-        looper.processMessages(1);
-        TextView emergencyText = (TextView) header.findViewById(
-                R.id.header_emergency_calls_only);
-        int subId = 0;
-        header.setMobileDataIndicators(null, null, 0, 0, false,
-                false, null, null, false, subId, true);
-        looper.processAllMessages();
-        assertEquals(mContext.getString(R.string.accessibility_data_connection_roaming),
-                emergencyText.getText());
-        assertEquals(View.VISIBLE, emergencyText.getVisibility());
-
-        header.setSubs(new ArrayList<>());
-        subId = 1;
-        header.setMobileDataIndicators(null, null, 0, 0, false,
-                false, null, null, false, subId, false);
-        looper.processAllMessages();
-
-        assertNotEquals(View.VISIBLE, emergencyText.getVisibility());
-        assertEquals(Looper.myLooper(), Looper.getMainLooper());
-        ViewUtils.detachView(header);
-        looper.processAllMessages();
-    }
-
-}