Merge "NoMan: Allow disabling SQLiteLog." into lmp-preview-dev
diff --git a/api/current.txt b/api/current.txt
index a829bdf..812dfc4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11570,16 +11570,6 @@
     method public void startTransition(int);
   }
 
-  public class VectorDrawable extends android.graphics.drawable.Drawable {
-    ctor public VectorDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public int getOpacity();
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setPadding(android.graphics.Rect);
-    method public void setPadding(int, int, int, int);
-  }
-
 }
 
 package android.graphics.drawable.shapes {
@@ -21693,9 +21683,7 @@
     method public abstract void cancel();
     method public abstract boolean hasVibrator();
     method public void vibrate(long);
-    method public void vibrate(long, int);
     method public void vibrate(long[], int);
-    method public void vibrate(long[], int, int);
   }
 
   public class WorkSource implements android.os.Parcelable {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f1391aa..bd07470 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3739,32 +3739,27 @@
      */
     public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
     /**
-     * This flag is used to break out "documents" into separate tasks that can
-     * be reached via the Recents mechanism. Such a document is any kind of
-     * item for which an application may want to maintain multiple simultaneous
-     * instances. Examples might be text files, web pages, spreadsheets, or
-     * emails. Each such document will be in a separate task in the Recents list.
+     * This flag is used to open a document into a new task rooted at the activity launched
+     * by this Intent. Through the use of this flag, or its equivalent attribute,
+     * {@link android.R.attr#documentLaunchMode} multiple instances of the same activity
+     * containing different douments will appear in the recent tasks list.
      *
-     * <p>When set, the activity specified by this Intent will launch into a
-     * separate task rooted at that activity. The activity launched must be
-     * defined with {@link android.R.attr#launchMode} <code>standard</code>
-     * or <code>singleTop</code>.
+     * <p>The use of the activity attribute form of this,
+     * {@link android.R.attr#documentLaunchMode}, is
+     * preferred over the Intent flag described here. The attribute form allows the
+     * Activity to specify multiple document behavior for all launchers of the Activity
+     * whereas using this flag requires each Intent that launches the Activity to specify it.
      *
-     * <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
-     * {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
-     * search for an existing task with a matching target activity and Intent
-     * data URI and relaunch that task, first finishing all activities down to
-     * the root activity and then calling the root activity's
-     * {@link android.app.Activity#onNewIntent(Intent)} method. If no existing
-     * task's root activity matches the Intent's data URI then a new task will
-     * be launched with the target activity as root.
+     * <p>FLAG_ACTIVITY_NEW_DOCUMENT may be used in conjunction with {@link
+     * #FLAG_ACTIVITY_MULTIPLE_TASK}. When used alone it is the
+     * equivalent of the Activity manifest specifying {@link
+     * android.R.attr#documentLaunchMode}="intoExisting". When used with
+     * FLAG_ACTIVITY_MULTIPLE_TASK it is the equivalent of the Activity manifest specifying
+     * {@link android.R.attr#documentLaunchMode}="always".
      *
-     * <p>When paired with {@link #FLAG_ACTIVITY_MULTIPLE_TASK} this will
-     * always create a new task. Thus the same document may be made to appear
-     * more than one time in Recents.
+     * Refer to {@link android.R.attr#documentLaunchMode} for more information.
      *
-     * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
-     *
+     * @see android.R.attr#documentLaunchMode
      * @see #FLAG_ACTIVITY_MULTIPLE_TASK
      */
     public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index c1d4d4c..cb0f142 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -74,6 +74,7 @@
      * @param streamHint An {@link AudioManager} stream type corresponding to the vibration type.
      *        For example, specify {@link AudioManager#STREAM_ALARM} for alarm vibrations or
      *        {@link AudioManager#STREAM_RING} for vibrations associated with incoming calls.
+     * @hide
      */
     public void vibrate(long milliseconds, int streamHint) {
         vibrate(Process.myUid(), mPackageName, milliseconds, streamHint);
@@ -125,6 +126,7 @@
      * @param streamHint An {@link AudioManager} stream type corresponding to the vibration type.
      *        For example, specify {@link AudioManager#STREAM_ALARM} for alarm vibrations or
      *        {@link AudioManager#STREAM_RING} for vibrations associated with incoming calls.
+     * @hide
      */
     public void vibrate(long[] pattern, int repeat, int streamHint) {
         vibrate(Process.myUid(), mPackageName, pattern, repeat, streamHint);
diff --git a/core/res/res/drawable/ic_audio_ring_notif.xml b/core/res/res/drawable/ic_audio_ring_notif.xml
index 247d1b4..b52db5c 100644
--- a/core/res/res/drawable/ic_audio_ring_notif.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif.xml
@@ -1,23 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
- * Copyright 2013, 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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#8A000000"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_mute.xml b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
index 72aaa9d..8d7d6cb 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_mute.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
@@ -1,23 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
- * Copyright 2013, 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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_mute_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#8A000000"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
+</vector>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
index 9e31aba..2f1d940 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
@@ -1,23 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
- * Copyright 2013, 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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_vibrate_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#8A000000"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
index 79401af..a358623 100644
--- a/core/res/res/layout/global_actions_silent_mode.xml
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -37,7 +37,7 @@
             android:layout_marginEnd="8dp"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
-            android:src="@drawable/ic_audio_vol_mute"
+            android:src="@drawable/ic_audio_ring_notif_mute"
             android:scaleType="center"
             android:duplicateParentState="true"
             android:background="@drawable/silent_mode_indicator"
@@ -94,7 +94,7 @@
             android:layout_marginEnd="8dp"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
-            android:src="@drawable/ic_audio_vol"
+            android:src="@drawable/ic_audio_ring_notif"
             android:scaleType="center"
             android:duplicateParentState="true"
             android:background="@drawable/silent_mode_indicator"
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
deleted file mode 100644
index 3ad1f23..0000000
--- a/core/res/res/layout/volume_adjust.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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"
-    android:id="@+id/visible_panel"
-    android:orientation="horizontal"
-    android:layout_width="300dp"
-    android:layout_height="wrap_content">
-
-    <LinearLayout
-        android:id="@+id/slider_group"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical">
-        <!-- Sliders go here -->
-    </LinearLayout>
-
-    <ImageView
-        android:id="@+id/expand_button_divider"
-        android:src="?attr/dividerVertical"
-        android:layout_width="wrap_content"
-        android:layout_height="32dip"
-        android:scaleType="fitXY"
-        android:layout_gravity="top"
-        android:layout_marginTop="16dip"
-        android:layout_marginBottom="16dip" />
-
-    <ImageView
-        android:id="@+id/expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:padding="16dip"
-        android:background="?attr/selectableItemBackground"
-        android:src="@drawable/ic_sysbar_quicksettings" />
-
-</LinearLayout>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b1f256e..acfbe2d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,41 +885,57 @@
          be passed a persistable Bundle in their Intent.extras. -->
     <attr name="persistable" format="boolean" />
 
-    <!-- Specify whether this activity should always be launched in doc-centric mode. For
-         values other than <code>none</code> the activity must be defined with
-         {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
-         This attribute can be overridden by {@link
-         android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+    <!-- This attribute specifies that an activity shall become the root activity of a
+         new task each time it is launched. Using this attribute permits the user to
+         have multiple documents from the same applications appear in the recent tasks list.
 
-         <p>If this attribute is not specified, <code>none</code> will be used.
-         Note that this launch behavior can be changed in some ways at runtime
-         through the {@link android.content.Intent} flags
-         {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+         <p>Such a document is any kind of item for which an application may want to
+         maintain multiple simultaneous instances. Examples might be text files, web
+         pages, spreadsheets, or emails. Each such document will be in a separate
+         task in the recent taskss list.
+
+         <p>This attribute is equivalent to adding the flag {@link
+         android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch
+         the activity.
+
+         <p>The documentLaunchMode attribute may be assigned one of three values, "none",
+         "intoExisting" and "always", described in detail below. For values other than
+         <code>none</code> the activity must be defined with
+         {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+         If this attribute is not specified, <code>none</code> will be used.
+         Note that <code>none</code> can be overridden at run time if the Intent used
+         to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+         Similarly <code>intoExisting</code> will be overridden by the flag
+         {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} combined with
+         {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. -->
     <attr name="documentLaunchMode">
         <!-- The default mode, which will create a new task only when
              {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
              Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
         <enum name="none" value="0" />
-        <!-- All tasks will be searched for a matching Intent. If one is found
-             That task will cleared and restarted with the root activity receiving a call
+        <!-- All tasks will be searched for one whose base Intent's ComponentName and
+             data URI match those of the launching Intent. If such a task is found
+             that task will be cleared and restarted with the root activity receiving a call
              to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
              such task is found a new task will be created.
-             This is the equivalent of with {@link
+             <p>This is the equivalent of launching an activity with {@link
              android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
-             without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
-             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+             set and without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK} set. -->
         <enum name="intoExisting" value="1" />
-        <!-- A new task rooted at this activity will be created.
-             This is the equivalent of with {@link
+        <!-- A new task rooted at this activity will be created. This will happen whether or
+             not there is an existing task whose ComponentName and data URI match
+             that of the launcing intent This is the equivalent of launching an activity
+             with {@link
              android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
-             paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
-             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+             and {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK} both set. -->
         <enum name="always" value="2" />
     </attr>
 
-    <!-- Tasks launched by activities with this attribute will remain in the recent task
+    <!-- Tasks launched by activities with this attribute will remain in the recent tasks
          list until the last activity in the task is completed. When that happens the task
-         will be automatically removed from the recent task list.
+         will be automatically removed from the recent tasks list.
 
          This attribute is the equivalent of {@link
          android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 52b021f..b0dc47d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -206,9 +206,6 @@
     <!-- Default width for a textview error popup -->
     <dimen name="textview_error_popup_default_width">240dip</dimen>
 
-    <!-- Volume panel y offset -->
-    <dimen name="volume_panel_top">16dp</dimen>
-
     <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
     <dimen name="default_app_widget_padding_left">8dp</dimen>
     <dimen name="default_app_widget_padding_top">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dcff978..69f73e5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -69,8 +69,6 @@
   <java-symbol type="id" name="edittext_container" />
   <java-symbol type="id" name="enter_pin_section" />
   <java-symbol type="id" name="expand_activities_button" />
-  <java-symbol type="id" name="expand_button" />
-  <java-symbol type="id" name="expand_button_divider" />
   <java-symbol type="id" name="expires_on" />
   <java-symbol type="id" name="find_next" />
   <java-symbol type="id" name="find_prev" />
@@ -161,9 +159,7 @@
   <java-symbol type="id" name="share" />
   <java-symbol type="id" name="shortcut" />
   <java-symbol type="id" name="skip_button" />
-  <java-symbol type="id" name="slider_group" />
   <java-symbol type="id" name="split_action_bar" />
-  <java-symbol type="id" name="stream_icon" />
   <java-symbol type="id" name="submit_area" />
   <java-symbol type="id" name="switch_new" />
   <java-symbol type="id" name="switch_old" />
@@ -181,7 +177,6 @@
   <java-symbol type="id" name="topPanel" />
   <java-symbol type="id" name="up" />
   <java-symbol type="id" name="value" />
-  <java-symbol type="id" name="visible_panel" />
   <java-symbol type="id" name="websearch" />
   <java-symbol type="id" name="wifi_p2p_wps_pin" />
   <java-symbol type="id" name="year" />
@@ -343,7 +338,6 @@
   <java-symbol type="dimen" name="search_view_preferred_width" />
   <java-symbol type="dimen" name="textview_error_popup_default_width" />
   <java-symbol type="dimen" name="toast_y_offset" />
-  <java-symbol type="dimen" name="volume_panel_top" />
   <java-symbol type="dimen" name="action_bar_stacked_max_height" />
   <java-symbol type="dimen" name="action_bar_stacked_tab_max_width" />
   <java-symbol type="dimen" name="notification_text_size" />
@@ -1199,8 +1193,6 @@
   <java-symbol type="layout" name="time_picker_legacy" />
   <java-symbol type="layout" name="time_picker_dialog" />
   <java-symbol type="layout" name="transient_notification" />
-  <java-symbol type="layout" name="volume_adjust" />
-  <java-symbol type="layout" name="volume_adjust_item" />
   <java-symbol type="layout" name="voice_interaction_session" />
   <java-symbol type="layout" name="web_text_view_dropdown" />
   <java-symbol type="layout" name="webview_find" />
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index e2bd50d..9a63fa3 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -101,6 +101,7 @@
  * <dd>Sets the Miter limit for a stroked path</dd></dt>
  * </dl>
  * </dd>
+ * @hide
  */
 public class VectorDrawable extends Drawable {
     private static final String LOGTAG = VectorDrawable.class.getSimpleName();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index c736fc7..5b620fd 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,9 @@
     private static final boolean USE_SESSIONS = true;
     private static final boolean DEBUG_SESSIONS = true;
 
+    /** Allow volume changes to set ringer mode to silent? */
+    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
+
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
@@ -1019,7 +1022,8 @@
             int newRingerMode;
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
-                                              : AudioManager.RINGER_MODE_SILENT;
+                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
+                        : AudioManager.RINGER_MODE_NORMAL;
             } else {
                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
             }
@@ -2552,7 +2556,9 @@
                     }
                 } else {
                     // (oldIndex < step) is equivalent to (old UI index == 0)
-                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                    if ((oldIndex < step)
+                            && VOLUME_SETS_RINGER_MODE_SILENT
+                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                         ringerMode = RINGER_MODE_SILENT;
                     }
                 }
@@ -2565,7 +2571,8 @@
                 break;
             }
             if ((direction == AudioManager.ADJUST_LOWER)) {
-                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                if (VOLUME_SETS_RINGER_MODE_SILENT
+                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                     ringerMode = RINGER_MODE_SILENT;
                 }
             } else if (direction == AudioManager.ADJUST_RAISE) {
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index 3a20c58..787eec5 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -24,5 +24,5 @@
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
new file mode 100644
index 0000000..2969948
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_ringer_silent.xml
new file mode 100644
index 0000000..b5837f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
new file mode 100644
index 0000000..d8ded58
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_vol_zen_off.xml b/packages/SystemUI/res/drawable/ic_vol_zen_off.xml
new file mode 100644
index 0000000..ea5ab70
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_vol_zen_off.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_vol_zen_on.xml b/packages/SystemUI/res/drawable/ic_vol_zen_on.xml
new file mode 100644
index 0000000..44024f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_vol_zen_on.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
new file mode 100644
index 0000000..e73b431
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/system_primary_color" >
+
+    <ImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:contentDescription="@string/accessibility_quick_settings_close"
+        android:padding="@dimen/qs_panel_padding"
+        android:src="@drawable/ic_qs_close" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@android:id/button1"
+        android:layout_toStartOf="@android:id/checkbox"
+        android:gravity="center_vertical"
+        android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+
+    <ImageView
+        android:id="@android:id/custom"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@android:id/title"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerHorizontal" />
+
+    <FrameLayout
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@android:id/custom" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
deleted file mode 100644
index 85b294d..0000000
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@color/system_secondary_color" >
-
-    <ImageView
-        android:id="@android:id/button1"
-        android:src="@drawable/ic_qs_close"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentStart="true"
-        android:padding="@dimen/qs_panel_padding" />
-
-    <Switch
-        android:id="@android:id/checkbox"
-        android:layout_width="wrap_content"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:gravity="center"
-        android:padding="@dimen/qs_panel_padding" />
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="match_parent"
-        android:layout_height="64dp"
-        android:layout_toEndOf="@android:id/button1"
-        android:layout_toStartOf="@android:id/checkbox"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:gravity="center_vertical"
-        android:paddingStart="@dimen/qs_panel_padding"
-        android:text="@string/zen_mode_title" />
-
-    <View
-        android:id="@android:id/custom"
-        android:layout_width="match_parent"
-        android:layout_height="2dp"
-        android:layout_below="@android:id/title"
-        android:background="#888" />
-
-    <ListView
-        android:id="@android:id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_above="@android:id/button2"
-        android:layout_below="@android:id/custom"
-        android:divider="#00000000"
-        android:dividerHeight="0px" />
-
-    <TextView
-        android:id="@android:id/button2"
-        style="@style/QSBorderless"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentEnd="true"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:padding="@dimen/qs_panel_padding"
-        android:text="@string/quick_settings_more_settings"
-        android:textAllCaps="true" />
-
-</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
deleted file mode 100644
index fd27aaf..0000000
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <RadioButton
-        android:id="@android:id/checkbox"
-        android:layout_width="32dp"
-        android:layout_height="64dp"
-        android:layout_alignParentStart="true"
-        android:layout_marginStart="@dimen/qs_panel_padding"
-        android:gravity="center" />
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="match_parent"
-        android:layout_height="64dp"
-        android:layout_toEndOf="@android:id/checkbox"
-        android:layout_toStartOf="@android:id/button1"
-        android:ellipsize="end"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:gravity="center_vertical"
-        android:maxLines="1"
-        android:text="@string/accessibility_back" />
-
-    <ImageView
-        android:id="@android:id/button1"
-        android:src="@drawable/ic_qs_minus"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:layout_marginEnd="48dp"
-        android:padding="@dimen/qs_panel_padding"
-        android:paddingRight="0px" />
-
-    <ImageView
-        android:id="@android:id/button2"
-        android:src="@drawable/ic_qs_plus"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:padding="@dimen/qs_panel_padding" />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index dfc3b22..7f34041 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -98,7 +98,8 @@
         android:gravity="center_vertical"
         android:ellipsize="marquee"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="#ffffff" />
+        android:textColor="#ffffff"
+        android:singleLine="true" />
 
     <include
         layout="@layout/quick_settings_brightness_dialog"
diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml
index 70c5042..816af57 100644
--- a/packages/SystemUI/res/layout/user_switcher_host.xml
+++ b/packages/SystemUI/res/layout/user_switcher_host.xml
@@ -27,7 +27,7 @@
     <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@*android:dimen/volume_panel_top"
+            android:layout_marginTop="@dimen/volume_panel_top"
             android:background="@*android:drawable/dialog_full_holo_dark">
         <ListView android:id="@android:id/list"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/volume_panel.xml b/packages/SystemUI/res/layout/volume_panel.xml
new file mode 100644
index 0000000..bc7288d
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/visible_panel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+
+    <FrameLayout
+        android:id="@+id/slider_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@+id/expand_button_divider" />
+
+    <ImageView
+        android:id="@+id/expand_button_divider"
+        android:layout_width="wrap_content"
+        android:layout_height="32dip"
+        android:layout_gravity="top"
+        android:layout_marginBottom="16dip"
+        android:layout_marginTop="16dip"
+        android:layout_toLeftOf="@+id/expand_button"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerVertical" />
+
+    <ImageView
+        android:id="@+id/expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_gravity="top"
+        style="@style/BorderlessButton.Tiny"
+        android:padding="16dip" />
+
+    <ImageView
+        android:id="@+id/zen_panel_divider"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/slider_panel"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerHorizontal" />
+
+    <ViewStub
+        android:id="@+id/zen_panel_stub"
+        android:layout_below="@+id/zen_panel_divider"
+        android:inflatedId="@+id/zen_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout="@layout/zen_mode_panel" />
+
+</RelativeLayout>
diff --git a/core/res/res/layout/volume_adjust_item.xml b/packages/SystemUI/res/layout/volume_panel_item.xml
similarity index 94%
rename from core/res/res/layout/volume_adjust_item.xml
rename to packages/SystemUI/res/layout/volume_panel_item.xml
index 57cecf4..98cb8f4 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/packages/SystemUI/res/layout/volume_panel_item.xml
@@ -27,7 +27,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:paddingLeft="16dip"
-        android:background="?attr/selectableItemBackground"
+        android:background="?android:attr/selectableItemBackground"
         android:contentDescription="@null" />
 
     <SeekBar
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
new file mode 100644
index 0000000..8b344000
--- /dev/null
+++ b/packages/SystemUI/res/layout/zen_mode_condition.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+
+    <RadioButton
+        android:id="@android:id/checkbox"
+        android:layout_width="32dp"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentStart="true"
+        android:gravity="center" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_toEndOf="@android:id/checkbox"
+        android:layout_toStartOf="@android:id/button1"
+        android:ellipsize="end"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
+
+    <ImageView
+        android:id="@android:id/button1"
+        style="@style/BorderlessButton"
+        android:layout_width="@dimen/zen_mode_condition_height"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
+        android:layout_marginEnd="@dimen/zen_mode_condition_height"
+        android:contentDescription="@string/accessibility_quick_settings_less_time"
+        android:padding="@dimen/zen_mode_condition_detail_button_padding"
+        android:src="@drawable/ic_qs_minus" />
+
+    <ImageView
+        android:id="@android:id/button2"
+        style="@style/BorderlessButton"
+        android:layout_width="@dimen/zen_mode_condition_height"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
+        android:contentDescription="@string/accessibility_quick_settings_more_time"
+        android:padding="@dimen/zen_mode_condition_detail_button_padding"
+        android:src="@drawable/ic_qs_plus" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
new file mode 100644
index 0000000..ae04bf5
--- /dev/null
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.volume.ZenModePanel xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/zen_mode_panel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/system_primary_color"
+    android:orientation="vertical"
+    android:padding="@dimen/qs_panel_padding" >
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_marginBottom="8dp"
+        android:text="@string/zen_mode_title"
+        android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+
+    <LinearLayout
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+
+    <TextView
+        android:id="@android:id/button2"
+        style="@style/BorderlessButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_gravity="end"
+        android:text="@string/quick_settings_more_settings"
+        android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+</com.android.systemui.volume.ZenModePanel>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0bd4f18..6405ae6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -135,5 +135,8 @@
     <!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
          be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
     <string name="velocity_tracker_impl" translatable="false">platform</string>
+
+    <!-- Wait on the touch feedback this long before performing an action. -->
+    <integer name="feedback_start_delay">300</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bf0cb68..6e35230 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -199,6 +199,9 @@
     <!-- How far the expanded QS panel peeks from the header in collapsed state. -->
     <dimen name="qs_peek_height">8dp</dimen>
 
+    <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
+    <dimen name="zen_mode_condition_height">48dp</dimen>
+
     <!-- used by DessertCase -->
     <dimen name="dessert_case_cell_size">192dp</dimen>
 
@@ -291,4 +294,9 @@
     <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
     <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
 
+    <!-- Volume panel dialog y offset -->
+    <dimen name="volume_panel_top">16dp</dimen>
+
+    <!-- Volume panel dialog width -->
+    <dimen name="volume_panel_width">300dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f5bc353..ef3956e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -388,6 +388,12 @@
     <string name="accessibility_quick_settings_location">Location <xliff:g id="state" example="Off">%s</xliff:g>.</string>
     <!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
+    <!-- Content description of quick settings detail panel close button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_close">Close panel</string>
+    <!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_more_time">More time</string>
+    <!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_less_time">Less time</string>
 
     <!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
     <string name="data_usage_disabled_dialog_3g_title">2G-3G data disabled</string>
@@ -512,6 +518,8 @@
     <string name="quick_settings_tethering_label">Tethering</string>
     <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_hotspot_label">Hotspot</string>
+    <!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_notifications_label">Notifications</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">RECENTS</string>
@@ -563,4 +571,19 @@
     <string name="keyguard_unlock">Swipe up to unlock</string>
 
     <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string>
+
+    <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_forever">Until you turn this off</string>
+
+    <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_minutes">
+        <item quantity="one">For one minute</item>
+        <item quantity="other">For %d minutes</item>
+    </plurals>
+
+    <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_hours">
+        <item quantity="one">For one hour</item>
+        <item quantity="other">For %d hours</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 19888a8..6a12232 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -133,6 +133,32 @@
         <item name="android:fadingEdge">horizontal</item>
     </style>
 
+    <style name="TextAppearance.QS">
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:fontFamily">sans-serif</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailHeader">
+        <item name="android:textSize">20sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailItemPrimary">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailItemSecondary">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">#7fcac3</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailButton">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
     <style name="BaseBrightnessDialogContainer">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
@@ -192,9 +218,9 @@
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
-    <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
+    <style name="BorderlessButton" parent="@android:style/Widget.Quantum.Button.Borderless" />
 
-    <style name="QSBorderless.Tiny">
+    <style name="BorderlessButton.Tiny">
         <item name="android:minHeight">12dip</item>
         <item name="android:minWidth">12dip</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index d7ce255..630ba13 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,12 +42,12 @@
     private final Class<?>[] SERVICES = new Class[] {
             com.android.systemui.keyguard.KeyguardViewMediator.class,
             com.android.systemui.recent.Recents.class,
+            com.android.systemui.volume.VolumeUI.class,
             com.android.systemui.statusbar.SystemBars.class,
             com.android.systemui.usb.StorageNotification.class,
             com.android.systemui.power.PowerUI.class,
             com.android.systemui.media.RingtonePlayer.class,
             com.android.systemui.settings.SettingsUI.class,
-            com.android.systemui.volume.VolumeUI.class,
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 835a5c4..c76ee8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -35,6 +36,7 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.TetheringController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.List;
 import java.util.Objects;
@@ -49,12 +51,12 @@
 public abstract class QSTile<TState extends State> implements Listenable {
     protected final String TAG = "QSTile." + getClass().getSimpleName();
     protected static final boolean DEBUG = false;
-    public static final int FEEDBACK_START_DELAY = 400;
 
     protected final Host mHost;
     protected final Context mContext;
     protected final H mHandler;
     protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
+    private final int mFeedbackStartDelay;
 
     private Callback mCallback;
     protected final TState mState = newTileState();
@@ -68,6 +70,7 @@
         mHost = host;
         mContext = host.getContext();
         mHandler = new H(host.getLooper());
+        mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
     }
 
     public boolean supportsDualTargets() {
@@ -116,6 +119,10 @@
         mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
     }
 
+    protected void postAfterFeedback(Runnable runnable) {
+        mHandler.postDelayed(runnable, mFeedbackStartDelay);
+    }
+
     // call only on tile worker looper
 
     private void handleSetCallback(Callback callback) {
@@ -213,6 +220,7 @@
         ZenModeController getZenModeController();
         TetheringController getTetheringController();
         CastController getCastController();
+        VolumeComponent getVolumeComponent();
     }
 
     public static class State {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 5eecc20..2edd8d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -84,7 +84,8 @@
             removeView(mLabel);
         }
         final Resources res = mContext.getResources();
-        mLabel = new TextView(mDual ? new ContextThemeWrapper(mContext, R.style.QSBorderless_Tiny)
+        mLabel = new TextView(mDual
+                ? new ContextThemeWrapper(mContext, R.style.BorderlessButton_Tiny)
                 : mContext);
         mLabel.setId(android.R.id.title);
         mLabel.setTextColor(res.getColor(R.color.qs_tile_text));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
index fa41837..07ea825 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -58,13 +58,13 @@
 
     @Override
     protected void handleClick() {
-        mHandler.postDelayed(new Runnable() {
+        postAfterFeedback(new Runnable() {
             @Override
             public void run() {
                 mHost.collapsePanels();
                 mUiHandler.post(mShowDialog);
             }
-        }, FEEDBACK_START_DELAY);
+        });
     }
 
     @Override
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 907c77e..6793051 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -65,12 +65,12 @@
 
     @Override
     protected void handleClick() {
-        mHandler.postDelayed(new Runnable() {
+        postAfterFeedback(new Runnable() {
             public void run() {
                 mHost.collapsePanels();
                 mUiHandler.post(mShowDialog);
             }
-        }, FEEDBACK_START_DELAY);
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
new file mode 100644
index 0000000..130f9ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -0,0 +1,172 @@
+/*
+ * 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.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.volume.VolumePanel;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Notifications **/
+public class NotificationsTile extends QSTile<NotificationsTile.NotificationsState> {
+    private final ZenModeController mZenController;
+    private final AudioManager mAudioManager;
+
+    public NotificationsTile(Host host) {
+        super(host);
+        mZenController = host.getZenModeController();
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    @Override
+    public View createDetailView(Context context, ViewGroup root) {
+        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
+        final View v = LayoutInflater.from(themedContext).inflate(R.layout.qs_detail, root, false);
+        final TextView title = (TextView) v.findViewById(android.R.id.title);
+        title.setText(R.string.quick_settings_notifications_label);
+        final View close = v.findViewById(android.R.id.button1);
+        close.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showDetail(false);
+            }
+        });
+        final ViewGroup content = (ViewGroup) v.findViewById(android.R.id.content);
+        final VolumeComponent volumeComponent = mHost.getVolumeComponent();
+        final VolumePanel vp = new VolumePanel(mContext, content, mZenController);
+        v.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                volumeComponent.setVolumePanel(null);
+            }
+
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                volumeComponent.setVolumePanel(vp);
+            }
+        });
+        vp.setZenModePanelCallback(new ZenModePanel.Callback() {
+            @Override
+            public void onMoreSettings() {
+                mHost.startSettingsActivity(ZenModePanel.ZEN_SETTINGS);
+            }
+
+            @Override
+            public void onInteraction() {
+                // noop
+            }
+        });
+        vp.postVolumeChanged(AudioManager.STREAM_NOTIFICATION, AudioManager.FLAG_SHOW_UI);
+        return v;
+    }
+
+    @Override
+    protected NotificationsState newTileState() {
+        return new NotificationsState();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mZenController.addCallback(mCallback);
+            final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mReceiver, filter);
+        } else {
+            mZenController.removeCallback(mCallback);
+            mContext.unregisterReceiver(mReceiver);
+        }
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mState.zen) {
+            mZenController.setZen(false);
+        } else {
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(NotificationsState state, Object arg) {
+        state.visible = true;
+        state.zen = arg instanceof Boolean ? (Boolean) arg : mZenController.isZen();
+        state.ringerMode = mAudioManager.getRingerMode();
+        if (state.zen) {
+            state.iconId = R.drawable.ic_qs_zen_on;
+        } else if (state.ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+            state.iconId = R.drawable.ic_qs_ringer_vibrate;
+        } else if (state.ringerMode == AudioManager.RINGER_MODE_SILENT) {
+            state.iconId = R.drawable.ic_qs_ringer_silent;
+        } else {
+            state.iconId = R.drawable.ic_qs_ringer_audible;
+        }
+        state.label = mContext.getString(R.string.quick_settings_notifications_label);
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
+            refreshState(zen);
+        }
+    };
+
+    public static final class NotificationsState extends QSTile.State {
+        public boolean zen;
+        public int ringerMode;
+
+        @Override
+        public boolean copyTo(State other) {
+            final NotificationsState o = (NotificationsState) other;
+            final boolean changed = o.zen != zen || o.ringerMode != ringerMode;
+            o.zen = zen;
+            o.ringerMode = ringerMode;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",zen=" + zen + ",ringerMode=" + ringerMode);
+            return rt;
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
deleted file mode 100644
index c5e9b52..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.tiles;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-
-/** Quick settings tile: Ringer mode **/
-public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
-
-    private final AudioManager mAudioManager;
-
-    public RingerModeTile(Host host) {
-        super(host);
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-    }
-
-    @Override
-    protected IntState newTileState() {
-        return new IntState();
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (listening) {
-            final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            mContext.registerReceiver(mReceiver, filter);
-        } else {
-            mContext.unregisterReceiver(mReceiver);
-        }
-    }
-
-    @Override
-    protected void handleClick() {
-        final int oldValue = (Integer) mState.value;
-        final int newValue =
-                oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
-              : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
-              : AudioManager.RINGER_MODE_NORMAL;
-
-        mAudioManager.setRingerMode(newValue);
-    }
-
-    @Override
-    protected void handleUpdateState(IntState state, Object arg) {
-        final int ringerMode = mAudioManager.getRingerMode();
-        state.visible = true;
-        state.value = ringerMode;
-        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-            state.iconId = R.drawable.ic_qs_ringer_vibrate;
-            state.label = "Vibrate";
-        } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
-            state.iconId = R.drawable.ic_qs_ringer_silent;
-            state.label = "Silent";
-        } else {
-            state.iconId = R.drawable.ic_qs_ringer_audible;
-            state.label = "Audible";
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
-                refreshState();
-            }
-        }
-    };
-
-    public static class IntState extends QSTile.State {
-        public int value;
-
-        @Override
-        public boolean copyTo(State other) {
-            final IntState o = (IntState) other;
-            final boolean changed = o.value != value;
-            o.value = value;
-            return super.copyTo(other) || changed;
-        }
-
-        @Override
-        protected StringBuilder toStringBuilder() {
-            final StringBuilder rt = super.toStringBuilder();
-            rt.insert(rt.length() - 1, ",value=" + value);
-            return rt;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
deleted file mode 100644
index f30f791..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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.tiles;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import java.util.HashSet;
-
-/** Quick settings control panel: Zen mode **/
-public class ZenModeDetail extends RelativeLayout {
-    private static final String TAG = "ZenModeDetail";
-    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
-    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
-
-    private final H mHandler = new H();
-
-    private int mMinutesIndex = 3;
-    private Context mContext;
-    private ZenModeTile mTile;
-    private QSTile.Host mHost;
-    private ZenModeController mController;
-
-    private Switch mSwitch;
-    private ConditionAdapter mAdapter;
-
-    public ZenModeDetail(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void init(ZenModeTile tile) {
-        mTile = tile;
-        mHost = mTile.getHost();
-        mContext = getContext();
-        mController = mHost.getZenModeController();
-
-        final ImageView close = (ImageView) findViewById(android.R.id.button1);
-        close.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mTile.showDetail(false);
-            }
-        });
-        mSwitch = (Switch) findViewById(android.R.id.checkbox);
-        mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mController.setZen(isChecked);
-            }
-        });
-        mSwitch.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final boolean isChecked = mSwitch.isChecked();
-                mController.setZen(isChecked);
-                if (!isChecked) {
-                    mTile.showDetail(false);
-                }
-            }
-        });
-
-        final View moreSettings = findViewById(android.R.id.button2);
-        moreSettings.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mHost.startSettingsActivity(ZEN_SETTINGS);
-                mTile.showDetail(false);
-            }
-        });
-        final ListView conditions = (ListView) findViewById(android.R.id.content);
-        mAdapter = new ConditionAdapter(mContext);
-        conditions.setAdapter(mAdapter);
-        mAdapter.add(updateTimeCondition());
-
-        updateZen(mController.isZen());
-    }
-
-    private Condition updateTimeCondition() {
-        final int minutes = MINUTES[mMinutesIndex];
-        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
-        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
-                .appendPath("countdown").appendPath(Long.toString(millis)).build();
-        final int num = minutes < 60 ? minutes : minutes / 60;
-        final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
-        return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
-                Condition.FLAG_RELEVANT_NOW);
-    }
-
-    private void editTimeCondition(int delta) {
-        final int i = mMinutesIndex + delta;
-        if (i < 0 || i >= MINUTES.length) return;
-        mMinutesIndex = i;
-        mAdapter.remove(mAdapter.getItem(0));
-        final Condition c = updateTimeCondition();
-        mAdapter.insert(c, 0);
-        select(c);
-    }
-
-    private void select(Condition condition) {
-        mController.select(condition);
-    }
-
-    private void updateZen(boolean zen) {
-        mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
-    }
-
-    private void updateConditions(Condition[] conditions) {
-        if (conditions == null) return;
-        mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
-    }
-
-    private void handleUpdateZen(boolean zen) {
-        mSwitch.setChecked(zen);
-    }
-
-    private void handleUpdateConditions(Condition[] conditions) {
-        for (int i = mAdapter.getCount() - 1; i > 0; i--) {
-            mAdapter.remove(mAdapter.getItem(i));
-        }
-        for (Condition condition : conditions) {
-            mAdapter.add(condition);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mController.addCallback(mCallback);
-        mController.requestConditions(true);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mController.removeCallback(mCallback);
-        mController.requestConditions(false);
-    }
-
-    private final class H extends Handler {
-        private static final int UPDATE_ZEN = 1;
-        private static final int UPDATE_CONDITIONS = 2;
-
-        public H() {
-            super(Looper.getMainLooper());
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == UPDATE_ZEN) {
-                handleUpdateZen(msg.arg1 == 1);
-            } else if (msg.what == UPDATE_CONDITIONS) {
-                handleUpdateConditions((Condition[])msg.obj);
-            }
-        }
-    }
-
-    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
-        @Override
-        public void onZenChanged(boolean zen) {
-            updateZen(zen);
-        }
-        public void onConditionsChanged(Condition[] conditions) {
-            updateConditions(conditions);
-        }
-    };
-
-    private final class ConditionAdapter extends ArrayAdapter<Condition> {
-        private final LayoutInflater mInflater;
-        private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
-
-        public ConditionAdapter(Context context) {
-            super(context, 0);
-            mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            final Condition condition = getItem(position);
-            final boolean enabled = condition.state == Condition.STATE_TRUE;
-
-            final View row = convertView != null ? convertView : mInflater
-                    .inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
-            final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
-            mRadioButtons.add(rb);
-            rb.setEnabled(enabled);
-            rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-                @Override
-                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                    if (isChecked) {
-                        for (RadioButton otherButton : mRadioButtons) {
-                            if (otherButton == rb) continue;
-                            otherButton.setChecked(false);
-                        }
-                        select(condition);
-                    }
-                }
-            });
-            final TextView title = (TextView) row.findViewById(android.R.id.title);
-            title.setText(condition.summary);
-            title.setEnabled(enabled);
-            title.setAlpha(enabled ? 1 : .5f);
-            final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
-            button1.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                    editTimeCondition(-1);
-                }
-            });
-
-            final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
-            button2.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                    editTimeCondition(1);
-                }
-            });
-            title.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                }
-            });
-            if (position != 0) {
-                button1.setVisibility(View.GONE);
-                button2.setVisibility(View.GONE);
-            }
-            if (position == 0 && mRadioButtons.size() == 1) {
-                rb.setChecked(true);
-            }
-            return row;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
deleted file mode 100644
index bfa9c19..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.tiles;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-/** Quick settings tile: Zen mode **/
-public class ZenModeTile extends QSTile<QSTile.BooleanState> {
-    private final ZenModeController mController;
-
-    public ZenModeTile(Host host) {
-        super(host);
-        mController = host.getZenModeController();
-    }
-
-    @Override
-    public View createDetailView(Context context, ViewGroup root) {
-        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
-        final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
-                .inflate(R.layout.qs_zen_mode_detail, root, false);
-        v.init(this);
-        return v;
-    }
-
-    @Override
-    protected BooleanState newTileState() {
-        return new BooleanState();
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mCallback);
-        } else {
-            mController.removeCallback(mCallback);
-        }
-    }
-
-    @Override
-    protected void handleClick() {
-        final boolean newZen = !mState.value;
-        mController.setZen(newZen);
-        if (newZen) {
-            showDetail(true);
-        }
-    }
-
-    @Override
-    protected void handleUpdateState(BooleanState state, Object arg) {
-        final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
-        state.value = zen;
-        state.visible = true;
-        state.iconId = zen ? R.drawable.ic_qs_zen_on : R.drawable.ic_qs_zen_off;
-        state.label = mContext.getString(R.string.zen_mode_title);
-    }
-
-    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
-        @Override
-        public void onZenChanged(boolean zen) {
-            if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
-            refreshState(zen);
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 27881c4..65e1cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -72,8 +72,7 @@
         window.setGravity(Gravity.TOP);
         WindowManager.LayoutParams lp = window.getAttributes();
         // Offset from the top
-        lp.y = getContext().getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.volume_panel_top);
+        lp.y = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
         lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
         lp.privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e3dac4a..dcd187c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -149,6 +149,7 @@
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
+        updateBackground();
         updateBackgroundResources();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b36c2ef..a3025e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -121,10 +121,12 @@
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -196,8 +198,9 @@
     NetworkControllerImpl mNetworkController;
     RotationLockControllerImpl mRotationLockController;
     UserInfoController mUserInfoController;
-    ZenModeControllerImpl mZenModeController;
+    ZenModeController mZenModeController;
     CastControllerImpl mCastController;
+    VolumeComponent mVolumeComponent;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
@@ -684,7 +687,8 @@
             mRotationLockController = new RotationLockControllerImpl(mContext);
         }
         mUserInfoController = new UserInfoController(mContext);
-        mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
+        mVolumeComponent = getComponent(VolumeComponent.class);
+        mZenModeController = mVolumeComponent.getZenController();
         mCastController = new CastControllerImpl(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
@@ -747,7 +751,7 @@
             final QSTileHost qsh = new QSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, null /*tethering*/,
-                    mCastController);
+                    mCastController, mVolumeComponent);
             for (QSTile<?> tile : qsh.getTiles()) {
                 mQSPanel.addTile(tile);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 7029898..1344703 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -21,6 +21,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
@@ -29,11 +30,10 @@
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
 import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.RingerModeTile;
+import com.android.systemui.qs.tiles.NotificationsTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.WifiTile;
-import com.android.systemui.qs.tiles.ZenModeTile;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.TetheringController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -60,13 +61,15 @@
     private final CastController mCast;
     private final Looper mLooper;
     private final CurrentUserTracker mUserTracker;
+    private final VolumeComponent mVolume;
     private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
+    private final int mFeedbackStartDelay;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
             BluetoothController bluetooth, LocationController location,
             RotationLockController rotation, NetworkController network,
             ZenModeController zen, TetheringController tethering,
-            CastController cast) {
+            CastController cast, VolumeComponent volume) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -76,6 +79,7 @@
         mZen = zen;
         mTethering = tethering;
         mCast = cast;
+        mVolume = volume;
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
         ht.start();
@@ -86,8 +90,7 @@
         mTiles.add(new ColorInversionTile(this));
         mTiles.add(new CellularTile(this));
         mTiles.add(new AirplaneModeTile(this));
-        mTiles.add(new ZenModeTile(this));
-        mTiles.add(new RingerModeTile(this));
+        mTiles.add(new NotificationsTile(this));
         mTiles.add(new RotationLockTile(this));
         mTiles.add(new LocationTile(this));
         mTiles.add(new CastTile(this));
@@ -103,6 +106,7 @@
             }
         };
         mUserTracker.startTracking();
+        mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
     }
 
     @Override
@@ -112,7 +116,7 @@
 
     @Override
     public void startSettingsActivity(final Intent intent) {
-        mStatusBar.postStartSettingsActivity(intent, QSTile.FEEDBACK_START_DELAY);
+        mStatusBar.postStartSettingsActivity(intent, mFeedbackStartDelay);
     }
 
     @Override
@@ -169,4 +173,9 @@
     public CastController getCastController() {
         return mCast;
     }
+
+    @Override
+    public VolumeComponent getVolumeComponent() {
+        return mVolume;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
new file mode 100644
index 0000000..5ee89253
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
@@ -0,0 +1,24 @@
+/*
+ * 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.volume;
+
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+public interface VolumeComponent {
+    ZenModeController getZenController();
+    void setVolumePanel(VolumePanel panel);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 8657e07..06f4c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -16,14 +16,12 @@
 
 package com.android.systemui.volume;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.DialogInterface.OnDismissListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
@@ -42,6 +40,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -49,6 +48,9 @@
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
+import com.android.internal.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
 import java.util.HashMap;
 
 /**
@@ -57,7 +59,6 @@
  * @hide
  */
 public class VolumePanel extends Handler {
-    private static final String TAG = VolumePanel.class.getSimpleName();
     private static boolean LOGD = false;
 
     private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
@@ -88,33 +89,48 @@
     private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
     private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
     private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
+    private static final int MSG_LAYOUT_DIRECTION = 12;
+    private static final int MSG_ZEN_MODE_CHANGED = 13;
 
     // Pseudo stream type for master volume
     private static final int STREAM_MASTER = -100;
     // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
 
+    private final String mTag;
     protected final Context mContext;
     private final AudioManager mAudioManager;
+    private final ZenModeController mZenController;
     private boolean mRingIsSilent;
-    private boolean mShowCombinedVolumes;
     private boolean mVoiceCapable;
+    private boolean mZenModeCapable;
 
     // True if we want to play tones on the system stream when the master stream is specified.
     private final boolean mPlayMasterStreamTones;
 
-    /** Dialog containing all the sliders */
-    private final Dialog mDialog;
-    /** Dialog's content view */
+
+    /** Volume panel content view */
     private final View mView;
+    /** Dialog hosting the panel, if not embedded */
+    private final Dialog mDialog;
+    /** Parent view hosting the panel, if embedded */
+    private final ViewGroup mParent;
 
     /** The visible portion of the volume overlay */
     private final ViewGroup mPanel;
-    /** Contains the sliders and their touchable icons */
-    private final ViewGroup mSliderGroup;
-    /** The button that expands the dialog to show all sliders */
-    private final View mMoreButton;
-    /** Dummy divider icon that needs to vanish with the more button */
-    private final View mDivider;
+    /** Contains the slider and its touchable icons */
+    private final ViewGroup mSliderPanel;
+    /** The button that expands the dialog to show the zen panel */
+    private final ImageView mExpandButton;
+    /** Dummy divider icon that needs to vanish with the expand button */
+    private final View mExpandDivider;
+    /** The zen mode configuration panel view stub */
+    private final ViewStub mZenPanelStub;
+    /** The zen mode configuration panel view, once inflated */
+    private ZenModePanel mZenPanel;
+    /** Dummy divider icon that needs to vanish with the zen panel */
+    private final View mZenPanelDivider;
+
+    private ZenModePanel.Callback mZenPanelCallback;
 
     /** Currently active stream that shows up at the top of the list of sliders */
     private int mActiveStreamType = -1;
@@ -129,8 +145,8 @@
                 false),
         RingerStream(AudioManager.STREAM_RING,
                 R.string.volume_icon_description_ringer,
-                R.drawable.ic_audio_ring_notif,
-                R.drawable.ic_audio_ring_notif_mute,
+                com.android.systemui.R.drawable.ic_ringer_audible,
+                com.android.systemui.R.drawable.ic_ringer_silent,
                 false),
         VoiceStream(AudioManager.STREAM_VOICE_CALL,
                 R.string.volume_icon_description_incall,
@@ -149,8 +165,8 @@
                 true),
         NotificationStream(AudioManager.STREAM_NOTIFICATION,
                 R.string.volume_icon_description_notification,
-                R.drawable.ic_audio_notification,
-                R.drawable.ic_audio_notification_mute,
+                com.android.systemui.R.drawable.ic_ringer_audible,
+                com.android.systemui.R.drawable.ic_ringer_silent,
                 true),
         // for now, use media resources for master volume
         MasterStream(STREAM_MASTER,
@@ -245,8 +261,11 @@
     }
 
 
-    public VolumePanel(Context context) {
+    public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) {
+        mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode());
         mContext = context;
+        mParent = parent;
+        mZenController = zenController;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         // For now, only show master volume if master volume is supported
@@ -258,74 +277,81 @@
                 streamRes.show = (streamRes.streamType == STREAM_MASTER);
             }
         }
-
-        mDialog = new Dialog(context) {
-            @Override
-            public boolean onTouchEvent(MotionEvent event) {
-                if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
-                        sConfirmSafeVolumeDialog == null) {
-                    forceTimeout();
-                    return true;
+        if (LOGD) Log.d(mTag, String.format("new VolumePanel hasParent=%s", parent != null));
+        final int layoutId = com.android.systemui.R.layout.volume_panel;
+        if (parent == null) {
+            // dialog mode
+            mDialog = new Dialog(context) {
+                @Override
+                public boolean onTouchEvent(MotionEvent event) {
+                    if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
+                            sConfirmSafeVolumeDialog == null) {
+                        forceTimeout();
+                        return true;
+                    }
+                    return false;
                 }
-                return false;
-            }
-        };
+            };
 
-        // Change some window properties
-        final Window window = mDialog.getWindow();
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        // Offset from the top
-        lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
-        lp.windowAnimations = R.style.Animation_VolumePanel;
-        window.setAttributes(lp);
-        window.setGravity(Gravity.TOP);
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-        window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
-                | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+            // Change some window properties
+            final Window window = mDialog.getWindow();
+            final LayoutParams lp = window.getAttributes();
+            lp.token = null;
+            // Offset from the top
+            lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+            lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.volume_panel_width);
+            lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+            lp.windowAnimations = R.style.Animation_VolumePanel;
+            window.setBackgroundDrawableResource(com.android.systemui.R.drawable.qs_panel_background);
+            window.setAttributes(lp);
+            window.setGravity(Gravity.TOP);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            window.requestFeature(Window.FEATURE_NO_TITLE);
+            window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+                    | LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+            mDialog.setCanceledOnTouchOutside(true);
+            mDialog.setContentView(layoutId);
+            mDialog.setOnDismissListener(new OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    mActiveStreamType = -1;
+                    mAudioManager.forceVolumeControlStream(mActiveStreamType);
+                }
+            });
 
-        mDialog.setCanceledOnTouchOutside(true);
-        mDialog.setContentView(R.layout.volume_adjust);
-        mDialog.setOnDismissListener(new OnDismissListener() {
-            @Override
-            public void onDismiss(DialogInterface dialog) {
-                mActiveStreamType = -1;
-                mAudioManager.forceVolumeControlStream(mActiveStreamType);
-            }
-        });
+            mDialog.create();
 
-        mDialog.create();
+            mView = window.findViewById(R.id.content);
+            mView.setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    resetTimeout();
+                    return false;
+                }
+            });
 
-        mView = window.findViewById(R.id.content);
-        mView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                resetTimeout();
-                return false;
-            }
-        });
-
-        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
-        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
-        mMoreButton = mView.findViewById(R.id.expand_button);
-        mDivider = mView.findViewById(R.id.expand_button_divider);
+        } else {
+            // embedded mode
+            mDialog = null;
+            mView = LayoutInflater.from(mContext).inflate(layoutId, parent, true);
+        }
+        mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel);
+        mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel);
+        mExpandButton = (ImageView) mView.findViewById(com.android.systemui.R.id.expand_button);
+        mExpandDivider = mView.findViewById(com.android.systemui.R.id.expand_button_divider);
+        mZenPanelStub = (ViewStub)mView.findViewById(com.android.systemui.R.id.zen_panel_stub);
+        mZenPanelDivider = mView.findViewById(com.android.systemui.R.id.zen_panel_divider);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
-        // If we don't want to show multiple volumes, hide the settings button
-        // and divider.
-        mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
-        if (!mShowCombinedVolumes) {
-            mMoreButton.setVisibility(View.GONE);
-            mDivider.setVisibility(View.GONE);
-        } else {
-            mMoreButton.setOnClickListener(mClickListener);
-        }
+        mZenModeCapable = !useMasterVolume && mZenController != null;
+        mZenPanelDivider.setVisibility(View.GONE);
+        mExpandButton.setOnClickListener(mClickListener);
+        updateZenMode(mZenController == null ? false : mZenController.isZen());
+        mZenController.addCallback(mZenCallback);
 
         final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
         final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
@@ -334,7 +360,7 @@
         listenToRingerMode();
     }
 
-    public void setLayoutDirection(int layoutDirection) {
+    private void setLayoutDirection(int layoutDirection) {
         mPanel.setLayoutDirection(layoutDirection);
         updateStates();
     }
@@ -406,21 +432,19 @@
             StreamResources streamRes = STREAMS[i];
 
             final int streamType = streamRes.streamType;
-            if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
-                streamRes = StreamResources.RingerStream;
-            }
 
             final StreamControl sc = new StreamControl();
             sc.streamType = streamType;
-            sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
+            sc.group = (ViewGroup) inflater.inflate(
+                    com.android.systemui.R.layout.volume_panel_item, null);
             sc.group.setTag(sc);
-            sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
+            sc.icon = (ImageView) sc.group.findViewById(com.android.systemui.R.id.stream_icon);
             sc.icon.setTag(sc);
             sc.icon.setContentDescription(res.getString(streamRes.descRes));
             sc.iconRes = streamRes.iconRes;
             sc.iconMuteRes = streamRes.iconMuteRes;
             sc.icon.setImageResource(sc.iconRes);
-            sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
+            sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
             final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
             sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
@@ -431,34 +455,18 @@
     }
 
     private void reorderSliders(int activeStreamType) {
-        mSliderGroup.removeAllViews();
+        mSliderPanel.removeAllViews();
 
         final StreamControl active = mStreamControls.get(activeStreamType);
         if (active == null) {
             Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
             mActiveStreamType = -1;
         } else {
-            mSliderGroup.addView(active.group);
+            mSliderPanel.addView(active.group);
             mActiveStreamType = activeStreamType;
             active.group.setVisibility(View.VISIBLE);
             updateSlider(active);
-        }
-
-        addOtherVolumes();
-    }
-
-    private void addOtherVolumes() {
-        if (!mShowCombinedVolumes) return;
-
-        for (int i = 0; i < STREAMS.length; i++) {
-            // Skip the phone specific ones and the active one
-            final int streamType = STREAMS[i].streamType;
-            if (!STREAMS[i].show || streamType == mActiveStreamType) {
-                continue;
-            }
-            StreamControl sc = mStreamControls.get(streamType);
-            mSliderGroup.addView(sc.group);
-            updateSlider(sc);
+            updateZenMode(mZenController == null ? false : mZenController.isZen());
         }
     }
 
@@ -472,7 +480,7 @@
         if (((sc.streamType == AudioManager.STREAM_RING) ||
                 (sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
                 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
-            sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
+            sc.icon.setImageResource(com.android.systemui.R.drawable.ic_ringer_vibrate);
         }
         if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
             // never disable touch interactions for remote playback, the muting is not tied to
@@ -486,32 +494,70 @@
         }
     }
 
+    public void setZenModePanelCallback(ZenModePanel.Callback callback) {
+        mZenPanelCallback = callback;
+    }
+
     private void expand() {
-        final int count = mSliderGroup.getChildCount();
-        for (int i = 0; i < count; i++) {
-            mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
+        if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel);
+        if (mZenPanel == null) {
+            mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
+            mZenPanel.init(mZenController);
+            mZenPanel.setCallback(new ZenModePanel.Callback() {
+                @Override
+                public void onMoreSettings() {
+                    if (mZenPanelCallback != null) {
+                        mZenPanelCallback.onMoreSettings();
+                    }
+                }
+
+                @Override
+                public void onInteraction() {
+                    if (mZenPanelCallback != null) {
+                        mZenPanelCallback.onInteraction();
+                    }
+                }
+            });
         }
-        mMoreButton.setVisibility(View.INVISIBLE);
-        mDivider.setVisibility(View.INVISIBLE);
+        mZenPanel.setVisibility(View.VISIBLE);
+        mZenPanelDivider.setVisibility(View.VISIBLE);
     }
 
     private void collapse() {
-        mMoreButton.setVisibility(View.VISIBLE);
-        mDivider.setVisibility(View.VISIBLE);
-        final int count = mSliderGroup.getChildCount();
-        for (int i = 1; i < count; i++) {
-            mSliderGroup.getChildAt(i).setVisibility(View.GONE);
+        if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel);
+        if (mZenPanel != null) {
+            mZenPanel.setVisibility(View.GONE);
         }
+        mZenPanelDivider.setVisibility(View.GONE);
     }
 
     public void updateStates() {
-        final int count = mSliderGroup.getChildCount();
+        final int count = mSliderPanel.getChildCount();
         for (int i = 0; i < count; i++) {
-            StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
+            StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
             updateSlider(sc);
         }
     }
 
+    private void updateZenMode(boolean zen) {
+        if (mZenModeCapable) {
+            final boolean show = mActiveStreamType == AudioManager.STREAM_NOTIFICATION
+                    || mActiveStreamType == AudioManager.STREAM_RING;
+            mExpandButton.setVisibility(show ? View.VISIBLE : View.GONE);
+            mExpandDivider.setVisibility(show ? View.VISIBLE : View.GONE);
+            mExpandButton.setImageResource(zen ? com.android.systemui.R.drawable.ic_vol_zen_on
+                    : com.android.systemui.R.drawable.ic_vol_zen_off);
+        } else {
+            mExpandButton.setVisibility(View.GONE);
+            mExpandDivider.setVisibility(View.GONE);
+        }
+    }
+
+    public void postZenModeChanged(boolean zen) {
+        removeMessages(MSG_ZEN_MODE_CHANGED);
+        obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0).sendToTarget();
+    }
+
     public void postVolumeChanged(int streamType, int flags) {
         if (hasMessages(MSG_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -582,8 +628,12 @@
     }
 
     public void postDismiss() {
-        removeMessages(MSG_TIMEOUT);
-        sendEmptyMessage(MSG_TIMEOUT);
+        forceTimeout();
+    }
+
+    public void postLayoutDirection(int layoutDirection) {
+        removeMessages(MSG_LAYOUT_DIRECTION);
+        obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection).sendToTarget();
     }
 
     /**
@@ -593,7 +643,7 @@
      */
     protected void onVolumeChanged(int streamType, int flags) {
 
-        if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
 
         if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
             synchronized (this) {
@@ -622,7 +672,7 @@
 
     protected void onMuteChanged(int streamType, int flags) {
 
-        if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
 
         StreamControl sc = mStreamControls.get(streamType);
         if (sc != null) {
@@ -638,7 +688,7 @@
         mRingIsSilent = false;
 
         if (LOGD) {
-            Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
+            Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType
                     + ", flags: " + flags + "), index: " + index);
         }
 
@@ -707,7 +757,7 @@
             }
 
             case AudioService.STREAM_REMOTE_MUSIC: {
-                if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); }
+                if (LOGD) { Log.d(mTag, "showing remote volume "+index+" over "+ max); }
                 break;
             }
         }
@@ -730,16 +780,18 @@
             }
         }
 
-        if (!mDialog.isShowing()) {
+        if (!isShowing()) {
             int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
             mAudioManager.forceVolumeControlStream(stream);
 
             // Showing dialog - use collapsed state
-            if (mShowCombinedVolumes) {
+            if (mZenModeCapable) {
                 collapse();
             }
-            mDialog.show();
+            if (mDialog != null) {
+                mDialog.show();
+            }
         }
 
         // Do a little vibrate if applicable (only when going into vibrate mode)
@@ -751,6 +803,10 @@
         }
     }
 
+    private boolean isShowing() {
+        return mDialog != null ? mDialog.isShowing() : mParent.isAttachedToWindow();
+    }
+
     protected void onPlaySound(int streamType, int flags) {
 
         if (hasMessages(MSG_STOP_SOUNDS)) {
@@ -795,9 +851,9 @@
         // streamType is the real stream type being affected, but for the UI sliders, we
         // refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real
         // stream type.
-        if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
 
-        if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) {
+        if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) {
             synchronized (this) {
                 if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
                     reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
@@ -805,7 +861,7 @@
                 onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags);
             }
         } else {
-            if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
+            if (LOGD) Log.d(mTag, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
         }
 
         if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
@@ -825,8 +881,8 @@
     }
 
     protected void onRemoteVolumeUpdateIfShown() {
-        if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()");
-        if (mDialog.isShowing()
+        if (LOGD) Log.d(mTag, "onRemoteVolumeUpdateIfShown()");
+        if (isShowing()
                 && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
                 && (mStreamControls != null)) {
             onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0);
@@ -842,7 +898,7 @@
      * @param visible
      */
     synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
-        if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
+        if (LOGD) Log.d(mTag, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
         boolean isVisible = (visible == 1);
         for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
             StreamResources streamRes = STREAMS[i];
@@ -857,7 +913,7 @@
     }
 
     protected void onDisplaySafeVolumeWarning(int flags) {
-        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || mDialog.isShowing()) {
+        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) {
             synchronized (sConfirmSafeVolumeLock) {
                 if (sConfirmSafeVolumeDialog != null) {
                     return;
@@ -907,7 +963,7 @@
                     mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
                 } catch (RuntimeException e) {
                     if (LOGD) {
-                        Log.d(TAG, "ToneGenerator constructor failed with "
+                        Log.d(mTag, "ToneGenerator constructor failed with "
                                 + "RuntimeException: " + e);
                     }
                 }
@@ -976,8 +1032,10 @@
             }
 
             case MSG_TIMEOUT: {
-                if (mDialog.isShowing()) {
-                    mDialog.dismiss();
+                if (isShowing()) {
+                    if (mDialog != null) {
+                        mDialog.dismiss();
+                    }
                     mActiveStreamType = -1;
                 }
                 synchronized (sConfirmSafeVolumeLock) {
@@ -988,7 +1046,7 @@
                 break;
             }
             case MSG_RINGER_MODE_CHANGED: {
-                if (mDialog.isShowing()) {
+                if (isShowing()) {
                     updateStates();
                 }
                 break;
@@ -1010,17 +1068,30 @@
             case MSG_DISPLAY_SAFE_VOLUME_WARNING:
                 onDisplaySafeVolumeWarning(msg.arg1);
                 break;
+
+            case MSG_LAYOUT_DIRECTION:
+                setLayoutDirection(msg.arg1);
+                break;
+
+            case MSG_ZEN_MODE_CHANGED:
+                updateZenMode(msg.arg1 != 0);
+                break;
         }
     }
 
-    private void resetTimeout() {
+    public void resetTimeout() {
+        if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis());
         removeMessages(MSG_TIMEOUT);
-        sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
+        sendEmptyMessageDelayed(MSG_TIMEOUT, TIMEOUT_DELAY);
     }
 
     private void forceTimeout() {
         removeMessages(MSG_TIMEOUT);
-        sendMessage(obtainMessage(MSG_TIMEOUT));
+        sendEmptyMessage(MSG_TIMEOUT);
+    }
+
+    public ZenModeController getZenController() {
+        return mZenController;
     }
 
     private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
@@ -1061,10 +1132,22 @@
     private final View.OnClickListener mClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (v == mMoreButton) {
-                expand();
+            if (v == mExpandButton && mZenController != null) {
+                final boolean newZen = !mZenController.isZen();
+                mZenController.setZen(newZen);
+                if (newZen) {
+                    expand();
+                } else {
+                    collapse();
+                }
             }
             resetTimeout();
         }
     };
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        public void onZenChanged(boolean zen) {
+            updateZenMode(zen);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 9bd75b7..7da90d8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -1,16 +1,22 @@
 package com.android.systemui.volume;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.IVolumeController;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 
 /*
  * Copyright (C) 2014 The Android Open Source Project
@@ -34,21 +40,21 @@
     private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING);
     private static final int DEFAULT = 1;  // enabled by default
 
+    private final Handler mHandler = new Handler();
     private AudioManager mAudioManager;
     private VolumeController mVolumeController;
 
     @Override
     public void start() {
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mVolumeController = new VolumeController(mContext);
+        putComponent(VolumeComponent.class, mVolumeController);
         updateController();
         mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver);
     }
 
     private void updateController() {
         if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) {
-            if (mVolumeController == null) {
-                mVolumeController = new VolumeController(mContext);
-            }
             Log.d(TAG, "Registering volume controller");
             mAudioManager.setVolumeController(mVolumeController);
         } else {
@@ -57,7 +63,7 @@
         }
     }
 
-    private final ContentObserver mObserver = new ContentObserver(new Handler()) {
+    private final ContentObserver mObserver = new ContentObserver(mHandler) {
         public void onChange(boolean selfChange, Uri uri) {
             if (SETTING_URI.equals(uri)) {
                 updateController();
@@ -66,13 +72,38 @@
     };
 
     /** For now, simply host an unmodified base volume panel in this process. */
-    private final class VolumeController extends IVolumeController.Stub {
-        private final VolumePanel mPanel;
+    private final class VolumeController extends IVolumeController.Stub implements VolumeComponent {
+        private final VolumePanel mDialogPanel;
+        private VolumePanel mPanel;
 
         public VolumeController(Context context) {
-            mPanel = new VolumePanel(context);
+            mPanel = new VolumePanel(context, null, new ZenModeControllerImpl(mContext, mHandler));
+            final int delay = context.getResources().getInteger(R.integer.feedback_start_delay);
+            mPanel.setZenModePanelCallback(new ZenModePanel.Callback() {
+                @Override
+                public void onMoreSettings() {
+                    mHandler.removeCallbacks(mStartZenSettings);
+                    mHandler.postDelayed(mStartZenSettings, delay);
+                }
+
+                @Override
+                public void onInteraction() {
+                    mDialogPanel.resetTimeout();
+                }
+            });
+            mDialogPanel = mPanel;
         }
 
+        private final Runnable mStartZenSettings = new Runnable() {
+            @Override
+            public void run() {
+                mDialogPanel.postDismiss();
+                final Intent intent = ZenModePanel.ZEN_SETTINGS;
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+            }
+        };
+
         @Override
         public void hasNewRemotePlaybackInfo() throws RemoteException {
             mPanel.postHasNewRemotePlaybackInfo();
@@ -114,12 +145,22 @@
         @Override
         public void setLayoutDirection(int layoutDirection)
                 throws RemoteException {
-            mPanel.setLayoutDirection(layoutDirection);
+            mPanel.postLayoutDirection(layoutDirection);
         }
 
         @Override
         public void dismiss() throws RemoteException {
             mPanel.postDismiss();
         }
+
+        @Override
+        public ZenModeController getZenController() {
+            return mDialogPanel.getZenController();
+        }
+
+        @Override
+        public void setVolumePanel(VolumePanel panel) {
+            mPanel = panel == null ? mDialogPanel : panel;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
new file mode 100644
index 0000000..77d267e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -0,0 +1,248 @@
+/*
+ * 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.volume;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class ZenModePanel extends LinearLayout {
+    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+    public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private final LayoutInflater mInflater;
+    private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
+    private final H mHandler = new H();
+    private LinearLayout mConditions;
+    private int mMinutesIndex = Arrays.binarySearch(MINUTES, 60);  // default to one hour
+    private Callback mCallback;
+    private ZenModeController mController;
+    private boolean mRequestingConditions;
+
+    public ZenModePanel(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mConditions = (LinearLayout) findViewById(android.R.id.content);
+        findViewById(android.R.id.button2).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                fireMoreSettings();
+            }
+        });
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        setRequestingConditions(visibility == VISIBLE);
+    }
+
+    /** Start or stop requesting relevant zen mode exit conditions */
+    private void setRequestingConditions(boolean requesting) {
+        if (mRequestingConditions == requesting) return;
+        mRequestingConditions = requesting;
+        if (mRequestingConditions) {
+            mController.addCallback(mZenCallback);
+        } else {
+            mController.removeCallback(mZenCallback);
+        }
+        mController.requestConditions(mRequestingConditions);
+    }
+
+    public void init(ZenModeController controller) {
+        mController = controller;
+        mConditions.removeAllViews();
+        bind(updateTimeCondition(), mConditions.getChildAt(0));
+        handleUpdateConditions(new Condition[0]);
+    }
+
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    private Condition updateTimeCondition() {
+        final int minutes = MINUTES[mMinutesIndex];
+        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
+        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
+                .appendPath("countdown").appendPath(Long.toString(millis)).build();
+        final int num = minutes < 60 ? minutes : minutes / 60;
+        final int resId = minutes < 60
+                ? R.plurals.zen_mode_duration_minutes
+                : R.plurals.zen_mode_duration_hours;
+        final String caption = mContext.getResources().getQuantityString(resId, num, num);
+        return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
+    private void handleUpdateConditions(Condition[] conditions) {
+        final int newCount = conditions == null ? 0 : conditions.length;
+        for (int i = mConditions.getChildCount() - 1; i > newCount; i--) {
+            mConditions.removeViewAt(i);
+        }
+        for (int i = 0; i < newCount; i++) {
+            bind(conditions[i], mConditions.getChildAt(i + 1));
+        }
+        bind(null, mConditions.getChildAt(newCount + 1));
+    }
+
+    private void editTimeCondition(int delta) {
+        final int i = mMinutesIndex + delta;
+        if (i < 0 || i >= MINUTES.length) return;
+        mMinutesIndex = i;
+        final Condition c = updateTimeCondition();
+        bind(c, mConditions.getChildAt(0));
+    }
+
+    private void bind(final Condition condition, View convertView) {
+        final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE;
+        final View row;
+        if (convertView == null) {
+            row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
+            mConditions.addView(row);
+        } else {
+            row = convertView;
+        }
+        final int position = mConditions.indexOfChild(row);
+        final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
+        mRadioButtons.add(rb);
+        rb.setEnabled(enabled);
+        rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    for (RadioButton otherButton : mRadioButtons) {
+                        if (otherButton == rb) continue;
+                        otherButton.setChecked(false);
+                    }
+                    mController.select(condition);
+                    fireInteraction();
+                }
+            }
+        });
+        final TextView title = (TextView) row.findViewById(android.R.id.title);
+        if (condition == null) {
+            title.setText(R.string.zen_mode_forever);
+        } else {
+            title.setText(condition.summary);
+        }
+        title.setEnabled(enabled);
+        title.setAlpha(enabled ? 1 : .5f);
+        final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
+        button1.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                editTimeCondition(-1);
+                fireInteraction();
+            }
+        });
+
+        final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
+        button2.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                editTimeCondition(1);
+                fireInteraction();
+            }
+        });
+        title.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                fireInteraction();
+            }
+        });
+        if (position == 0) {
+            button1.setEnabled(mMinutesIndex > 0);
+            button2.setEnabled(mMinutesIndex < MINUTES.length - 1);
+            button1.setImageAlpha(button1.isEnabled() ? 0xff : 0x7f);
+            button2.setImageAlpha(button2.isEnabled() ? 0xff : 0x7f);
+        } else {
+            button1.setVisibility(View.GONE);
+            button2.setVisibility(View.GONE);
+        }
+        if (position == 0 &&  mConditions.getChildCount() == 1) {
+            rb.setChecked(true);
+        }
+    }
+
+    private void fireMoreSettings() {
+        if (mCallback != null) {
+            mCallback.onMoreSettings();
+        }
+    }
+
+    private void fireInteraction() {
+        if (mCallback != null) {
+            mCallback.onInteraction();
+        }
+    }
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        @Override
+        public void onConditionsChanged(Condition[] conditions) {
+            mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int UPDATE_CONDITIONS = 1;
+
+        private H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == UPDATE_CONDITIONS) {
+                handleUpdateConditions((Condition[])msg.obj);
+            }
+        }
+    }
+
+    public interface Callback {
+        void onMoreSettings();
+        void onInteraction();
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 88bebcb..1755472 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9574,11 +9574,13 @@
                 return;
             }
 
-            mRecentTasks = mTaskPersister.restoreTasksLocked();
-            if (!mRecentTasks.isEmpty()) {
-                mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);
+            if (mRecentTasks == null) {
+                mRecentTasks = mTaskPersister.restoreTasksLocked();
+                if (!mRecentTasks.isEmpty()) {
+                    mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);
+                }
+                mTaskPersister.startPersisting();
             }
-            mTaskPersister.startPersisting();
 
             // Check to see if there are any update receivers to run.
             if (!mDidUpdate) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index b948c41..b429b93 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1154,13 +1154,15 @@
         }
 
         if (intent == null) {
-            Slog.e(TAG, "restoreActivity error intent=" + intent);
-            return null;
+            throw new XmlPullParserException("restoreActivity error intent=" + intent);
         }
 
         final ActivityManagerService service = stackSupervisor.mService;
         final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
                 null, userId);
+        if (aInfo == null) {
+            throw new XmlPullParserException("restoreActivity resolver error.");
+        }
         final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
                 launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
                 null, null, 0, componentSpecified, stackSupervisor, null, null);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d0ba118..d96e5eb 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -37,6 +37,7 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
@@ -346,6 +347,12 @@
         mWindowManager = mService.mWindowManager;
         mStackId = activityContainer.mStackId;
         mCurrentUser = mService.mCurrentUserId;
+        // Get the activity screenshot thumbnail dimensions
+        Resources res = mService.mContext.getResources();
+        mThumbnailWidth =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
+        mThumbnailHeight =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
     }
 
     /**
@@ -729,42 +736,54 @@
         }
     }
 
+    /**
+     * This resets the saved state from the last screenshot, forcing a new screenshot to be taken
+     * again when requested.
+     */
+    private void invalidateLastScreenshot() {
+        mLastScreenshotActivity = null;
+        if (mLastScreenshotBitmap != null) {
+            mLastScreenshotBitmap.recycle();
+        }
+        mLastScreenshotBitmap = null;
+    }
+
     public final Bitmap screenshotActivities(ActivityRecord who) {
+        if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who);
         if (who.noDisplay) {
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tNo display");
             return null;
         }
 
         TaskRecord tr = who.task;
-        if (mService.getMostRecentTask() != tr && tr.intent != null &&
-                (tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0) {
-            // If this task is being excluded from recents, we don't want to take
-            // the expense of capturing a thumbnail, since we will never show it.
+        if (mService.getMostRecentTask() != tr || isHomeStack()) {
+            // This is an optimization -- since we never show Home or Recents within Recents itself,
+            // we can just go ahead and skip taking the screenshot if this is the home stack.  In
+            // the case where the most recent task is not the task that was supplied, then the stack
+            // has changed, so invalidate the last screenshot().
+            invalidateLastScreenshot();
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tIs Home stack? " + isHomeStack());
             return null;
         }
 
-        Resources res = mService.mContext.getResources();
         int w = mThumbnailWidth;
         int h = mThumbnailHeight;
-        if (w < 0) {
-            mThumbnailWidth = w =
-               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
-            mThumbnailHeight = h =
-               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
-        }
-
         if (w > 0) {
             if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null
                     || mLastScreenshotActivity.state == ActivityState.RESUMED
                     || mLastScreenshotBitmap.getWidth() != w
                     || mLastScreenshotBitmap.getHeight() != h) {
+                if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tUpdating screenshot");
                 mLastScreenshotActivity = who;
                 mLastScreenshotBitmap = mWindowManager.screenshotApplications(
                         who.appToken, Display.DEFAULT_DISPLAY, w, h, SCREENSHOT_FORCE_565);
             }
             if (mLastScreenshotBitmap != null) {
+                if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tReusing last screenshot");
                 return mLastScreenshotBitmap.copy(mLastScreenshotBitmap.getConfig(), true);
             }
         }
+        Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
         return null;
     }
 
@@ -1042,6 +1061,12 @@
         } else {
             next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
         }
+
+        // If we are resuming the activity that we had last screenshotted, then we know it will be
+        // updated, so invalidate the last screenshot to ensure we take a fresh one when requested
+        if (next == mLastScreenshotActivity) {
+            invalidateLastScreenshot();
+        }
     }
 
     private void setVisibile(ActivityRecord r, boolean visible) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c1a4643..ae7fab3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -109,6 +109,7 @@
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_STATES = DEBUG || false;
     static final boolean DEBUG_IDLE = DEBUG || false;
+    static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
 
@@ -1212,8 +1213,7 @@
             requestCode = sourceRecord.requestCode;
             sourceRecord.resultTo = null;
             if (resultRecord != null) {
-                resultRecord.removeResultsLocked(
-                    sourceRecord, resultWho, requestCode);
+                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
             }
             if (sourceRecord.launchedFromUid == callingUid) {
                 // The new activity is being launched from the same uid as the previous
@@ -1385,7 +1385,7 @@
         return err;
     }
 
-    ActivityStack adjustStackFocus(ActivityRecord r) {
+    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
         if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
             if (task != null) {
@@ -1410,7 +1410,8 @@
                 return container.mStack;
             }
 
-            if (mFocusedStack != mHomeStack) {
+            if (mFocusedStack != mHomeStack && (!newTask ||
+                    mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                         "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
@@ -1463,7 +1464,7 @@
 
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
-        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+        mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
         if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
 
         // If the caller has asked not to resume at this point, we make note
@@ -1473,7 +1474,8 @@
             r.delayedResume = true;
         }
 
-        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+        ActivityRecord notTop =
+                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
 
         // If the onlyIfNeeded flag is set, then we can do this if the activity
         // being launched is the same as the one making the call...  or, as
@@ -1496,9 +1498,11 @@
             case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                 intent.addFlags(
                         Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                launchFlags = intent.getFlags();
                 break;
             case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+                launchFlags = intent.getFlags();
                 break;
         }
         final boolean newDocument = intent.isDocument();
@@ -1804,7 +1808,8 @@
                 Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
-            targetStack = adjustStackFocus(r);
+            newTask = true;
+            targetStack = adjustStackFocus(r, newTask);
             targetStack.moveToFront();
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
@@ -1821,7 +1826,6 @@
             } else {
                 r.setTask(reuseTask, reuseTask, true);
             }
-            newTask = true;
             if (!movedHome) {
                 if ((launchFlags &
                         (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
@@ -1889,7 +1893,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = adjustStackFocus(r);
+            targetStack = adjustStackFocus(r, newTask);
             targetStack.moveToFront();
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task
@@ -2316,7 +2320,12 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (!r.isApplicationActivity() && !stack.isHomeStack()) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
+                    continue;
+                }
+                if (!stack.mActivityContainer.isEligibleForNewTasks()) {
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
+                            stack);
                     continue;
                 }
                 final ActivityRecord ar = stack.findTaskLocked(r);
@@ -3247,6 +3256,11 @@
         void setDrawn() {
         }
 
+        // You can always start a new task on a regular ActivityStack.
+        boolean isEligibleForNewTasks() {
+            return true;
+        }
+
         @Override
         public String toString() {
             return mIdString + (mActivityDisplay == null ? "N" : "A");
@@ -3327,6 +3341,12 @@
             }
         }
 
+        // Never start a new task on an ActivityView if it isn't explicitly specified.
+        @Override
+        boolean isEligibleForNewTasks() {
+            return false;
+        }
+
         private void setSurfaceIfReady() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index ba3f2fe..3bfaca9 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -155,6 +155,7 @@
             File taskFile = recentFiles[taskNdx];
             if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
             BufferedReader reader = null;
+            boolean deleteFile = false;
             try {
                 reader = new BufferedReader(new FileReader(taskFile));
                 final XmlPullParser in = Xml.newPullParser();
@@ -183,10 +184,9 @@
                     }
                     XmlUtils.skipCurrentTag(in);
                 }
-            } catch (IOException e) {
-                Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e);
-            } catch (XmlPullParserException e) {
-                Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e);
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error " + e);
+                deleteFile = true;
             } finally {
                 if (reader != null) {
                     try {
@@ -194,6 +194,9 @@
                     } catch (IOException e) {
                     }
                 }
+                if (!DEBUG && deleteFile) {
+                    taskFile.delete();
+                }
             }
         }
 
@@ -220,7 +223,7 @@
         return new ArrayList<TaskRecord>(Arrays.asList(tasksArray));
     }
 
-    private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
+    private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
         for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
             File file = files[fileNdx];
             String filename = file.getName();
@@ -285,8 +288,7 @@
                 synchronized(mService) {
                     final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
                     persistentTaskIds.clear();
-                    int taskNdx;
-                    for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                    for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                         task = tasks.get(taskNdx);
                         if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
                                 task.isPersistable + " needsPersisting=" + task.needsPersisting);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6fbb39d..c23d1ea 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3189,6 +3189,7 @@
             WindowState win = atoken.findMainWindow();
             Rect containingFrame = new Rect(0, 0, width, height);
             Rect contentInsets = new Rect();
+            boolean isFullScreen = true;
             if (win != null) {
                 if (win.mContainingFrame != null) {
                     containingFrame.set(win.mContainingFrame);
@@ -3196,11 +3197,11 @@
                 if (win.mContentInsets != null) {
                     contentInsets.set(win.mContentInsets);
                 }
+                isFullScreen =
+                        ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) ==
+                                SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
             }
 
-            boolean isFullScreen =
-                    ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
-                            == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
                     mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen);
             if (a != null) {