Merge "Remove renderer abstract class"
diff --git a/api/current.txt b/api/current.txt
index c0ad9c6..6749453 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5478,7 +5478,6 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5527,7 +5526,6 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
diff --git a/api/system-current.txt b/api/system-current.txt
index deaa5f0..b2e44a3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5578,7 +5578,6 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5628,7 +5627,6 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 3074b49..d1e40ae 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -165,15 +165,24 @@
     /** @hide */
     public static class PolicyInfo {
         public final int ident;
-        final public String tag;
-        final public int label;
-        final public int description;
+        public final String tag;
+        public final int label;
+        public final int description;
+        public final int labelForSecondaryUsers;
+        public final int descriptionForSecondaryUsers;
 
-        public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
-            ident = identIn;
-            tag = tagIn;
-            label = labelIn;
-            description = descriptionIn;
+        public PolicyInfo(int ident, String tag, int label, int description) {
+            this(ident, tag, label, description, label, description);
+        }
+
+        public PolicyInfo(int ident, String tag, int label, int description,
+                int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
+            this.ident = ident;
+            this.tag = tag;
+            this.label = label;
+            this.description = description;
+            this.labelForSecondaryUsers = labelForSecondaryUsers;
+            this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
         }
     }
 
@@ -184,7 +193,10 @@
     static {
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
                 com.android.internal.R.string.policylab_wipeData,
-                com.android.internal.R.string.policydesc_wipeData));
+                com.android.internal.R.string.policydesc_wipeData,
+                com.android.internal.R.string.policylab_wipeData_secondaryUser,
+                com.android.internal.R.string.policydesc_wipeData_secondaryUser
+                ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
                 com.android.internal.R.string.policylab_resetPassword,
                 com.android.internal.R.string.policydesc_resetPassword));
@@ -193,7 +205,10 @@
                 com.android.internal.R.string.policydesc_limitPassword));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
                 com.android.internal.R.string.policylab_watchLogin,
-                com.android.internal.R.string.policydesc_watchLogin));
+                com.android.internal.R.string.policydesc_watchLogin,
+                com.android.internal.R.string.policylab_watchLogin,
+                com.android.internal.R.string.policydesc_watchLogin_secondaryUser
+        ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
                 com.android.internal.R.string.policylab_forceLock,
                 com.android.internal.R.string.policydesc_forceLock));
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d0ebdbd..c5b6320 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2710,6 +2710,7 @@
      * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
      * then it's up to the TrustAgent itself to aggregate the values from all device admins.
      * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
+     * @hide
      */
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
             PersistableBundle configuration) {
@@ -2735,6 +2736,7 @@
      * for this {@param agent} or calls it with a null configuration, null is returned.
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
+     * @hide
      */
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
             ComponentName agent) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index bb162153..adab9be 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -132,6 +132,19 @@
             float requestedRefreshRate, boolean inTraversal);
 
     /**
+     * Applies an offset to the contents of a display, for example to avoid burn-in.
+     * <p>
+     * TODO: Technically this should be associated with a physical rather than logical
+     * display but this is good enough for now.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param x The X offset by which to shift the contents of the display.
+     * @param y The Y offset by which to shift the contents of the display.
+     */
+    public abstract void setDisplayOffsets(int displayId, int x, int y);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..8e9eb48 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -78,7 +78,10 @@
 
     /**
      *  Bit field indicating that street addresses should be matched in methods that
-     *  take an options mask
+     *  take an options mask. Note that this uses the
+     *  {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+     *  {@link android.webkit.WebView} for finding addresses, which has various
+     *  limitations.
      */
     public static final int MAP_ADDRESSES = 0x08;
 
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 54a0025..0814101 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2006 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.
@@ -4171,12 +4172,6 @@
         return mMediaController;
     }
 
-    private boolean isTranslucent() {
-        TypedArray a = getWindowStyle();
-        return a.getBoolean(a.getResourceId(
-                R.styleable.Window_windowIsTranslucent, 0), false);
-    }
-
     @Override
     public void setEnterTransition(Transition enterTransition) {
         mEnterTransition = enterTransition;
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d617c05..89990c2 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -19,6 +19,7 @@
 import android.animation.TimeInterpolator;
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -38,6 +39,7 @@
     private static final String TAG = "SwipeDismissLayout";
 
     private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+    private boolean mUseDynamicTranslucency = true;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -85,7 +87,7 @@
                     // and temporarily disables translucency when it is fully visible.
                     // As soon as the user starts swiping, we will re-enable
                     // translucency.
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertFromTranslucent();
                     }
                 }
@@ -117,6 +119,11 @@
                 android.R.integer.config_shortAnimTime);
         mCancelInterpolator = new DecelerateInterpolator(1.5f);
         mDismissInterpolator = new AccelerateInterpolator(1.5f);
+        TypedArray a = context.getTheme().obtainStyledAttributes(
+                com.android.internal.R.styleable.Theme);
+        mUseDynamicTranslucency = !a.hasValue(
+                com.android.internal.R.styleable.Window_windowIsTranslucent);
+        a.recycle();
     }
 
     public void setOnDismissedListener(OnDismissedListener listener) {
@@ -230,7 +237,7 @@
                 mLastX = ev.getRawX();
                 updateSwiping(ev);
                 if (mSwiping) {
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertToTranslucent(null, null);
                     }
                     setProgress(ev.getRawX() - mDownX);
@@ -254,7 +261,7 @@
     }
 
     protected void cancel() {
-        if (getContext() instanceof Activity) {
+        if (mUseDynamicTranslucency && getContext() instanceof Activity) {
             ((Activity) getContext()).convertFromTranslucent();
         }
         if (mProgressListener != null) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1dd10e1..28f1a3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
 LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
 LOCAL_CPPFLAGS += -Wno-conversion-null
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 1afcf73..36f7963 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -160,7 +160,8 @@
 android_eglGetDisplayInt
   (JNIEnv *_env, jobject _this, jint display_id) {
 
-    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+    if (static_cast<uintptr_t>(display_id) !=
+        reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
         jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
         return 0;
     }
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 713fff9..226162d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -1935,7 +1935,11 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        // The cast below is incorrect. The driver will end up writing to the
+        // address specified by name, which will always crash the process since
+        // it is guaranteed to be in low memory. The additional static_cast
+        // suppresses the warning for now. http://b/19478262
+        (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3643,7 +3647,7 @@
         (GLenum)mode,
         (GLsizei)count,
         (GLenum)type,
-        (GLvoid *)indicesOffset,
+        (GLvoid *)static_cast<uintptr_t>(indicesOffset),
         (GLsizei)instanceCount
     );
 }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 2df13b7..6c95b8a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -159,7 +159,7 @@
     }
 
     struct logger_list *logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NONBLOCK, 0, 0);
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
 
     if (!logger_list) {
         jniThrowIOException(env, errno);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6094fd1..4b97138 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -300,6 +300,8 @@
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
 
+    <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6bb61a2..09103e3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -329,7 +329,9 @@
         <attr name="windowOverscan" format="boolean" />
         <!-- Flag indicating whether this is a floating window. -->
         <attr name="windowIsFloating" format="boolean" />
-        <!-- Flag indicating whether this is a translucent window. -->
+        <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
+             not if set to false), the window might still be considered translucent, if
+             windowSwipeToDismiss is set to true. -->
         <attr name="windowIsTranslucent" format="boolean" />
         <!-- Flag indicating that this window's background should be the
              user's current wallpaper.  Corresponds
@@ -455,7 +457,9 @@
         <attr name="windowTranslucentNavigation" format="boolean" />
 
         <!-- Flag to indicate that a window can be swiped away to be dismissed.
-             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
+             dynamically change translucency of the window, if the windowIsTranslucent is not set.
+             If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
         <attr name="windowSwipeToDismiss" format="boolean" />
 
         <!-- Flag indicating whether this window requests that content changes be performed
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4c0520e..fd8b803 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2074,4 +2074,23 @@
     <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
          panning to scaling the magnification viewport. -->
     <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
+
+    <!-- If true, the display will be shifted around in ambient mode. -->
+    <bool name="config_enableBurnInProtection">false</bool>
+
+    <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
+         will be used. -->
+    <integer name="config_burnInProtectionMaxRadius">-1</integer>
+
+    <!-- Specifies the minimum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>
+
+    <!-- Specifies the minimum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMinVerticalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d95b17e..199b783 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2396,7 +2396,7 @@
     <!-- Title of policy access to limiting the user's password choices -->
     <string name="policylab_limitPassword">Set password rules</string>
     <!-- Description of policy access to limiting the user's password choices -->
-    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
+    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen lock passwords and PINs.</string>
     <!-- Title of policy access to watch user login attempts -->
     <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
     <!-- Description of policy access to watch user login attempts -->
@@ -2411,15 +2411,24 @@
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
     typed. when unlocking the screen, and lock the phone or erase all the phone\'s
     data if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the tablet or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the TV or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the phone or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
     <!-- Title of policy access to reset user's password -->
-    <string name="policylab_resetPassword">Change the screen-unlock password</string>
+    <string name="policylab_resetPassword">Change the screen lock</string>
     <!-- Description of policy access to reset user's password -->
-    <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
+    <string name="policydesc_resetPassword">Change the screen lock.</string>
     <!-- Title of policy access to force lock the device -->
     <string name="policylab_forceLock">Lock the screen</string>
     <!-- Description of policy access to limiting the user's password choices -->
     <string name="policydesc_forceLock">Control how and when the screen locks.</string>
-    <!-- Title of policy access to wipe the user's data -->
+    <!-- Title of policy access to wipe primary user's data -->
     <string name="policylab_wipeData">Erase all data</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
@@ -2427,15 +2436,23 @@
     <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
-    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Title of policy access to wipe secondary user's data -->
+    <string name="policylab_wipeData_secondaryUser">Erase user data</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
+    <!-- Title of policy access to set global proxy -->
+    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Description of policy access to set global proxy -->
     <string name="policydesc_setGlobalProxy">Set the device global proxy
-        to be used while policy is enabled. Only the first device admin
-        sets the effective global proxy.</string>
+    to be used while policy is enabled. Only the device owner can set the global proxy.</string>
     <!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
-    <string name="policylab_expirePassword">Set lock-screen password expiration</string>
+    <string name="policylab_expirePassword">Set screen lock password expiration</string>
     <!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
-    <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
+    <string name="policydesc_expirePassword">Change how frequently the screen lock password, PIN, or pattern must be changed.</string>
     <!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
     <string name="policylab_encryptedStorage">Set storage encryption</string>
     <!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
@@ -2445,9 +2462,9 @@
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
     <string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
     <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
-    <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
+    <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
-    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -5073,7 +5090,7 @@
     <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
 
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever">Indefinitely</string>
+    <string name="zen_mode_forever">Until you turn this off</string>
 
     <!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
     <string name="toolbar_collapse_description">Collapse</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 615f445..39c0e8f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,7 @@
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
   <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+  <java-symbol type="bool" name="config_enableBurnInProtection" />
   <java-symbol type="bool" name="config_hotswapCapable" />
   <java-symbol type="bool" name="config_mms_content_disposition_support" />
   <java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -344,6 +345,11 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+  <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -754,7 +760,9 @@
   <java-symbol type="string" name="policydesc_resetPassword" />
   <java-symbol type="string" name="policydesc_setGlobalProxy" />
   <java-symbol type="string" name="policydesc_watchLogin" />
+  <java-symbol type="string" name="policydesc_watchLogin_secondaryUser" />
   <java-symbol type="string" name="policydesc_wipeData" />
+  <java-symbol type="string" name="policydesc_wipeData_secondaryUser" />
   <java-symbol type="string" name="policydesc_disableKeyguardFeatures" />
   <java-symbol type="string" name="policylab_disableCamera" />
   <java-symbol type="string" name="policylab_encryptedStorage" />
@@ -765,6 +773,7 @@
   <java-symbol type="string" name="policylab_setGlobalProxy" />
   <java-symbol type="string" name="policylab_watchLogin" />
   <java-symbol type="string" name="policylab_wipeData" />
+  <java-symbol type="string" name="policylab_wipeData_secondaryUser" />
   <java-symbol type="string" name="policylab_disableKeyguardFeatures" />
   <java-symbol type="string" name="postalTypeCustom" />
   <java-symbol type="string" name="postalTypeHome" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 1ebc708..e730dff 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,9 +24,6 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
@@ -42,9 +39,6 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index bed4b4d..45bd76a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -48,6 +48,11 @@
 provided by the Device Administration API to provide stronger security for
 employee devices that are powered by Android.</p>
 
+<p class="note"><strong>Note</strong> For information on building a Work Policy
+Controller for Android for Work deployments, see <a
+href="{@docRoot}training/enterprise/work-policy-ctrl.html">Building a Work
+Policy Controller</a>.</p>
+
 
 <h2 id="overview">Device Administration API Overview</h2>
 
@@ -712,4 +717,4 @@
 </pre>
 <p>
 See the Device Administration API sample for a complete example of how to enable storage encryption.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/images/enterprise/work-launcher.png b/docs/html/images/enterprise/work-launcher.png
new file mode 100644
index 0000000..3bbd835
--- /dev/null
+++ b/docs/html/images/enterprise/work-launcher.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 6fb906e..9caf938 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1186,5 +1186,21 @@
       "training/multiscreen/index.html",
       "training/monitoring-device-state/index.html"
     ]
+  },
+  "training/work/apps": {
+    "title": "",
+    "resources": [
+      "training/enterprise/app-compatibility.html",
+      "training/enterprise/app-restrictions.html",
+      "samples/AppRestrictionSchema/index.html",
+      "samples/AppRestrictionEnforcer/index.html"
+    ]
+  },
+  "training/work/admin": {
+    "title": "",
+    "resources": [
+      "training/enterprise/work-policy-ctrl.html",
+      "samples/BasicManagedProfile/index.html"
+    ]
   }
 }
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index d899ef3..45d1890 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -124,7 +124,7 @@
     <li>If the SDK is not already installed, follow the setup wizard to install the SDK and any
     necessary SDK tools.
     <p class="note"><strong>Note:</strong> You may also need to install the ia32-libs,
-    lib32ncurses5-dev, and lib32stc++6 packages. These packages are required to support 32-bit apps
+    lib32ncurses5-dev, and lib32stdc++6 packages. These packages are required to support 32-bit apps
     on a 64-bit machine. </p>
     </li>
   </ol>
diff --git a/docs/html/tools/help/android.jd b/docs/html/tools/help/android.jd
index 19891e8..0d7d2aa 100644
--- a/docs/html/tools/help/android.jd
+++ b/docs/html/tools/help/android.jd
@@ -6,25 +6,26 @@
 <p>{@code android} is an important development tool that lets you:</p>
 
   <ul>
-    <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href= 
-    "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command
-Line</a>.</li>
+    <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
+    "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command Line</a>.</li>
 
-    <li>Create and update Android projects. See <a href= 
+    <li>Create and update Android projects. See <a href=
     "{@docRoot}tools/projects/projects-cmdline.html">Managing Projects from
     the Command Line</a>.</li>
 
-    <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href= 
-    "{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</li>
-  </ul>If you are using Eclipse, the <code>android</code> tool's features are integrated
-  into ADT, so you should not need to use this tool directly.
-  
+    <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
+    "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
+  </ul>
+
+<p>If you are using Android Studio or Eclipse, the <code>android</code> tool's features are
+integrated into the IDE, so you should not need to use this tool directly. </p>
+
   <p class="note"><strong>Note:</strong> The documentation of options below is not exhaustive
 and may be out of date. For the most current list of options, execute <code>android
 --help</code>.</p>
-  
-  
-  
+
+
+
 
   <h2>Syntax</h2>
   <pre>android [global options] action [action options]</pre>
diff --git a/docs/html/training/enterprise/app-compatibility.jd b/docs/html/training/enterprise/app-compatibility.jd
index 1ae1ee3..216a799 100644
--- a/docs/html/training/enterprise/app-compatibility.jd
+++ b/docs/html/training/enterprise/app-compatibility.jd
@@ -1,4 +1,6 @@
 page.title=Ensuring Compatibility with Managed Profiles
+page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices.
+
 @jd:body
 
 <div id="tb-wrapper">
diff --git a/docs/html/training/enterprise/app-restrictions.jd b/docs/html/training/enterprise/app-restrictions.jd
new file mode 100644
index 0000000..fc5dfcc
--- /dev/null
+++ b/docs/html/training/enterprise/app-restrictions.jd
@@ -0,0 +1,351 @@
+page.title=Implementing App Restrictions
+page.metaDescription=Learn how to implement app restrictions and configuration settings that can be changed by other apps on the same device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#define_restrictions">Define App Restrictions</a></li>
+ <li><a href="#check_restrictions">Check App Restrictions</a></li>
+ <li><a href="#listen">Listen for App Restriction Changes</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>Resources</h2>
+<ul>
+  <li><a href="{@docRoot}samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a>
+    sample app</li>
+  <li><a href="{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+    sample app</li>
+</ul>
+
+</div>
+</div>
+
+<p>If you are developing apps for the enterprise market, you may need to satisfy
+particular requirements set by a company's policies. Application restrictions
+allow the enterprise administrator to remotely specify settings for apps.
+This capability is particularly useful for enterprise-approved apps deployed to
+a managed profile.</p>
+
+<p>For example, an enterprise might require that approved apps allow the
+enterprise administrator to:</p>
+
+<ul>
+  <li>Whitelist or blacklist URLs for a web browser</li>
+  <li>Configure whether an app is allowed to sync content via cellular, or just
+    by Wi-Fi</li>
+  <li>Configure the app's email settings</li>
+</ul>
+
+<p>
+  This guide shows how to implement these configuration settings in your app.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> For historical reasons, these configuration settings are known as
+  <em>restrictions,</em> and are implemented with files and classes that use this
+  term (such as {@link android.content.RestrictionsManager}). However, these
+  restrictions can actually implement a wide range of configuration options,
+  not just restrictions on app functionality.
+</p>
+
+<h2 id="overview">
+  Remote Configuration Overview
+</h2>
+
+<p>
+  Apps define the restrictions and configuration options that can be remotely
+  set by an administrator. These restrictions are
+  arbitrary configuration settings that can be changed by a restrictions
+  provider. If your app is running on an enterprise device's managed
+  profile, the enterprise administrator can change your app's restrictions.
+</p>
+
+<p>
+  The restrictions provider is another app running on the same device.
+  This app is typically controlled by the enterprise administrator. The
+  enterprise administrator communicates restriction changes to the restrictions
+  provider app. That app, in turn, changes the restrictions on your app.
+</p>
+
+<p>
+  To provide externally configurable restrictions:
+</p>
+
+<ul>
+  <li>Declare the restrictions in your app manifest. Doing so allows the
+  enterprise administrator to read the app's restrictions through Google
+  Play APIs.
+  </li>
+
+  <li>Whenever the app resumes, use the {@link
+    android.content.RestrictionsManager} object to check the current
+    restrictions, and change your app's UI and behavior to conform with those
+    restrictions.
+  </li>
+
+  <li>Listen for the
+  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
+  broadcast, check the {@link android.content.RestrictionsManager} to see what
+  the current restrictions are, and make any necessary changes to your app's
+  behavior.
+  </li>
+</ul>
+
+<h2 id="define_restrictions">
+  Define App Restrictions
+</h2>
+
+<p>
+  Your app can support any restrictions you want to define. You declare the
+  app's restrictions in a <em>restrictions file</em>, and declare the
+  restrictions file in the manifest. Creating a restrictions file allows other
+  apps to examine the restrictions your app provides. Enterprise Mobility
+  Management (EMM) partners can read your app's restrictions by using Google
+  Play APIs.
+</p>
+
+<p>
+  To define your app's remote configuration options, put the following element
+  in your manifest's
+  <a href="{@docRoot}guide/topics/manifest/application-element.html">
+  <code>&lt;application&gt;</code></a> element:
+</p>
+
+<pre>&lt;meta-data android:name="android.content.APP_RESTRICTIONS"
+    android:resource="@xml/app_restrictions" /&gt;
+</pre>
+
+<p>
+  Create a file named <code>app_restrictions.xml</code> in your app's
+  <code>res/xml</code> directory. The structure of that file is described in
+  the reference for {@link android.content.RestrictionsManager}. The file has a
+  single top-level <code>&lt;restrictions&gt;</code> element, which contains
+  one <code>&lt;restriction&gt;</code> child element for every configuration
+  option the app has.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> Do not create localized versions of the restrictions
+  file. Your app is only allowed to have a single restrictions file,
+  so restrictions will be consistent for your app in all locales.
+</p>
+
+<p>
+  In an enterprise environment, an EMM will typically use the restrictions
+  schema to generate a remote console for IT administrators, so the
+  administrators can remotely configure your application.
+</p>
+
+<p>
+  For example, suppose your app can be remotely configured to allow or forbid
+  it to download data over a cellular connection. Your app could have a
+  <code>&lt;restriction&gt;</code> element like this:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+
+  &lt;restriction
+    android:key="downloadOnCellular"
+    android:title="App is allowed to download data via cellular"
+    android:restrictionType="bool"
+    android:description="If 'false', app can only download data via Wi-Fi"
+    android:defaultValue="true" /&gt;
+
+&lt;/restrictions&gt;
+</pre>
+
+<p>
+  The supported types for the <code>android:restrictionType</code> element are
+  documented in the reference for {@link android.content.RestrictionsManager}.
+</p>
+
+<p>
+  You use each restriction's <code>android:key</code> attribute to read its
+  value from a restrictions bundle. For this reason, each restriction must have
+  a unique key string, and the string <em>cannot</em> be localized. It must be
+  specified with a string literal.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> In a production app, <code>android:title</code> and
+  <code>android:description</code> should be drawn from a localized resource
+  file, as described in <a href=
+  "{@docRoot}guide/topics/resources/localization.html">Localizing with
+  Resources</a>.
+</p>
+
+<p>
+  The restrictions provider can query the app to find details on the app's
+  available restrictions, including their description text. Restrictions
+  providers and enterprise administrators can change your app's restrictions at
+  any time, even when the app is not running.
+</p>
+
+<h2 id="check_restrictions">
+  Check App Restrictions
+</h2>
+
+<p>
+  Your app is not automatically notified when other apps change its restriction
+  settings. Instead, you need to check what the restrictions are when your app
+  starts or resumes, and listen for a system intent to find out if the
+  restrictions change while your app is running.
+</p>
+
+<p>
+  To find out the current restriction settings, your app uses a {@link
+  android.content.RestrictionsManager} object. Your app should check for the
+  current restrictions at the following times:
+</p>
+
+<ul>
+  <li>When the app starts or resumes, in its
+  {@link android.app.Activity#onResume onResume()} method
+  </li>
+
+  <li>When the app is notified of a restriction change, as described in
+    <a href="#listen">Listen for Device Configuration
+    Changes</a>
+  </li>
+</ul>
+
+<p>
+  To get a {@link android.content.RestrictionsManager} object, get the current
+  activity with {@link android.app.Fragment#getActivity getActivity()}, then
+  call that activity's {@link android.app.Activity#getSystemService
+  Activity.getSystemService()} method:
+</p>
+
+<pre>RestrictionsManager myRestrictionsMgr =
+    (RestrictionsManager) getActivity()
+        .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
+
+<p>
+  Once you have a {@link android.content.RestrictionsManager}, you can get the current restrictions
+  settings by calling its
+  {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method:
+</p>
+
+<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
+
+<p class="note">
+  <strong>Note:</strong> For convenience, you can also fetch the current
+  restrictions with a {@link android.os.UserManager}, by calling {@link
+  android.os.UserManager#getApplicationRestrictions
+  UserManager.getApplicationRestrictions()}. This method behaves exactly the
+  same as {@link android.content.RestrictionsManager#getApplicationRestrictions
+  RestrictionsManager.getApplicationRestrictions()}.
+</p>
+
+<p>
+  The {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method requires reading from data storage, so
+  it should be done sparingly. Do not call this method every time you need to
+  know the current restrictions. Instead, you should call it once when your app
+  starts or resumes, and cache the fetched restrictions bundle. Then listen for
+  the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
+  change while your app is active, as described in <a href="#listen">Listen for
+  Device Configuration Changes</a>.
+</p>
+
+<h3 id="read_restrictions">
+  Reading and applying restrictions
+</h3>
+
+<p>
+  The {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method returns a {@link android.os.Bundle}
+  containing a key-value pair for each restriction that has been set. The
+  values are all of type <code>Boolean</code>, <code>int</code>,
+  <code>String</code>, and <code>String[]</code>. Once you have the
+  restrictions {@link android.os.Bundle}, you can check the current
+  restrictions settings with the standard {@link android.os.Bundle} methods for
+  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
+  or
+  {@link android.os.Bundle#getString getString()}.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The restrictions {@link android.os.Bundle} contains
+  one item for every restriction that has been explicitly set by a restrictions
+  provider. However, you <em>cannot</em> assume that a restriction will be
+  present in the bundle just because you defined a default value in the
+  restrictions XML file.
+</p>
+
+<p>
+  It is up to your app to take appropriate action based on the current
+  restrictions settings. For example, if your app has a restriction specifying
+  whether it can download data over a cellular connection, and you find that
+  the restriction is set to <code>false</code>, you would have to disable data
+  download except when the device has a Wi-Fi connection, as shown in the
+  following example code:
+</p>
+
+<pre>
+boolean appCanUseCellular;
+
+if appRestrictions.containsKey("downloadOnCellular") {
+    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
+} else {
+    // here, cellularDefault is a boolean set with the restriction's
+    // default value
+    appCanUseCellular = cellularDefault;
+}
+
+if (!appCanUseCellular) {
+    // ...turn off app's cellular-download functionality
+    // ...show appropriate notices to user
+}</pre>
+
+<h2 id="listen">
+  Listen for App Restriction Changes
+</h2>
+
+<p>
+  Whenever an app's restrictions are changed, the system fires the
+  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
+  this intent so you can change the app's behavior when the restriction settings
+  change. The following code shows how to dynamically register a broadcast
+  receiver for this intent:
+</p>
+
+<pre>IntentFilter restrictionsFilter =
+    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+
+BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
+  &#64;Override public void onReceive(Context context, Intent intent) {
+
+    // Get the current restrictions bundle
+    Bundle <code>appRestrictions</code> =
+
+    myRestrictionsMgr.getApplicationRestrictions();
+
+    // Check current restrictions settings, change your app's UI and
+    // functionality as necessary.
+
+  }
+
+};
+
+registerReceiver(restrictionsReceiver, restrictionsFilter);
+</pre>
+<p class="note">
+  <strong>Note:</strong> Ordinarily, your app does not need to be notified
+  about restriction changes when it is paused. Instead, you should unregister
+  your broadcast receiver when the app is paused. When the app resumes, you
+  first check for the current restrictions (as discussed in <a href=
+  "#check_restrictions">Check Device Restrictions</a>), then register your
+  broadcast receiver to make sure you're notified about restriction changes
+  that happen while the app is active.
+</p>
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
index 0ac68cc..10be14e 100644
--- a/docs/html/training/enterprise/index.jd
+++ b/docs/html/training/enterprise/index.jd
@@ -1,58 +1,67 @@
-page.title=Developing for Enterprise
-page.tags=policy,privacy
-
-trainingnavtop=true
-startpage=true
-next.title=Enhancing Security with Device Management Policies
-next.link=device-management-policy.html
+page.title=Building Apps for Work
+meta.tags="work, enterprise, corporate"
+page.tags="work", "enterprise", "corporate"
+page.metaDescription=Learn how to build Android apps for the enterprise and take advantage of Google's Android for Work program.
+page.tags="education"
+page.article=true
 
 @jd:body
 
-<div id="tb-wrapper">
-<div id="tb">
+<img src="{@docRoot}images/enterprise/work-launcher.png"
+  width="300"
+  style="float:right;margin:0 0 20px 20px"
+  alt="Android for Work apps in a managed profile">
 
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
-  <li>Android 2.2 (API Level 8) or higher</li>
-</ul>
+<p>
+  The Android framework provides features to support the security, data separation, and
+  administration needs of a enterprise environment. As an app developer, you can make your app more
+  appealing to corporate customers by gracefully handling enterprise security and feature
+  restrictions. You can also modify your app so that technology administrators can remotely
+  configure it for use with enterprise resources.
+</p>
 
-<!-- related docs (NOT javadocs) -->
-<h2>You should also read</h2>
-<ul>
-  <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
-</ul>
+<p>
+  To help businesses incorporate Android devices and apps into the workplace, Google provides the
+  <a href="http://www.google.com/work/android">Android for Work</a> program, which offers a suite
+  of APIs and services for device distribution and administration. Through this program companies
+  can connect with Enterprise Mobility Management (EMM) providers to help integrate Android with
+  their businesses.
+</p>
 
-<h2>Try it out</h2>
+<p>
+  For more information, follow the links below to learn how to update your Android app to support
+  the enterprise environment or build enterprise-specific solutions.
+</p>
 
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
-class="button">Download the sample</a>
- <p class="filename">DeviceManagement.zip</p>
-</div>
 
-</div>
+<h2 id="apps">App Development for Enterprises</h2>
+
+<p>
+  Learn how to make your app function smoothly in corporate environments that restrict device
+  features and data access. Go further to support enterprise use of your app by enabling
+  restrictions that corporate technology administrators can use to remotely configure your app:
+</p>
+
+<div class="dynamic-grid">
+  <div class="resource-widget resource-flow-layout landing col-12"
+    data-query="collection:training/work/apps"
+    data-cardSizes="9x3"
+    data-maxResults="6">
+  </div>
 </div>
 
 
-<p>In this class, you'll learn APIs and techniques you can use when developing applications
-for the enterprise.</p>
+<h2 id="admin">Device and App Administration</h2>
 
+<p>
+  Learn how to build policy controller apps that enable enterprise technology administrators
+  to manage devices, manage corporate apps, and provide access to company resources:
+</p>
 
-<h2>Lessons</h2>
-
-
-<dl>
-  <dt><b><a href="device-management-policy.html">Enhancing Security with Device Management
-Policies</a></b></dt>
-    <dd>In this lesson, you will learn how to create a security-aware application that manages
-access to its content by enforcing device management policies</dd>
-
-  <dt><b><a href="app-compatibility.html">Ensuring Compatibility with Managed Profiles</a></b></dt>
-
-    <dd>In this lesson, you will learn the best practices to follow to ensure
-      that your app functions properly on devices that use <a
-      href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed
-      profiles</a></dd>
-
-</dl>
+<div class="dynamic-grid">
+  <div class="resource-widget resource-flow-layout landing col-12"
+    data-query="collection:training/work/admin"
+    data-cardSizes="9x3"
+    data-maxResults="4">
+  </div>
+</div>
diff --git a/docs/html/training/enterprise/work-policy-ctrl.jd b/docs/html/training/enterprise/work-policy-ctrl.jd
new file mode 100644
index 0000000..5854e65
--- /dev/null
+++ b/docs/html/training/enterprise/work-policy-ctrl.jd
@@ -0,0 +1,339 @@
+page.title=Building a Work Policy Controller
+page.metaDescription=Learn how to develop a Work Policy Controller to create and administer a managed profile on an employee's device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#after_creating_profile">Create a Managed Profile</a></li>
+ <li><a href="#set_up_policies">Set Up Device Policies</a></li>
+ <li><a href="#apply_restrictions">Apply App Restrictions</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+
+<h2>
+  You should also read
+</h2>
+
+<ul>
+  <li>
+    <a href="{@docRoot}guide/topics/admin/device-admin.html">Device
+    Administration</a>
+  </li>
+</ul>
+
+<h2>Resources</h2>
+<ul>
+
+  <li>
+    <a href=
+    "{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>
+  </li>
+
+  <li>
+    <a href=
+    "{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+  </li>
+</ul>
+
+</div>
+</div>
+
+
+<p>
+  In an Android for Work deployment, an enterprise needs to maintain control
+  over certain aspects of the employees' devices. The enterprise needs to
+  ensure that work-related information is encrypted and is kept separate from
+  employees' personal data. The enterprise may also need to limit device
+  capabilities, such as whether the device is allowed to use its camera. And
+  the enterprise may require that approved apps provide app restrictions, so
+  the enterprise can turn app capability on or off as needed.
+</p>
+
+<p>
+  To handle these tasks, an enterprise develops and deploys a Work Policy
+  Controller app. This app is installed on each employee's device. The
+  controller app installed on each employee's device and creates a work user
+  profile, which accesses enterprise apps and data separately from the user's
+  personal account. The controller app also acts as the
+  bridge between the enterprise's management software and the device; the
+  enterprise tells the controller app when it needs to make configuration
+  changes, and the controller app makes the appropriate settings changes for the
+  device and for other apps.
+</p>
+
+<p>
+  This lesson describes how to develop a Work Policy Controller app for devices
+  in an Android for Work deployment. The lesson describes how to create a work
+  user profile, how to set device policies, and how to apply
+  restrictions to other apps running on the managed profile.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> This lesson does not cover the situation where the
+  only profile on the device is the managed profile, under the enterprise's
+  control.
+</p>
+
+<h2 id="overview">Device Administration Overview</h2>
+
+<p>
+  In an Android for Work deployment, the enterprise administrator can set
+  policies to control the behavior of employees' devices and apps. The
+  enterprise administrator sets these policies with software provided by their
+  Enterprise Mobility Management (EMM) provider. The EMM software communicates
+  with a Work Policy Controller on each device. The Work Policy Controller, in
+  turn, manages the settings and behavior of the work user profile on each
+  individual’s device.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> A Work Policy Controller is built on the existing
+  model used for device administration applications, as described in <a href=
+  "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>.
+  In particular, your app needs to create a subclass of {@link
+  android.app.admin.DeviceAdminReceiver}, as described in that document.
+</p>
+
+<h3 id="managed_profiles">Managed profiles</h3>
+
+<p>
+  Users often want to use their personal devices in an enterprise setting. This
+  situation can present enterprises with a dilemma. If the user can use their
+  own device, the enterprise has to worry that confidential information (like
+  employee emails and contacts) are on a device the enterprise does not
+  control.
+</p>
+
+<p>
+  To address this situation, Android 5.0 (API level 21) allows enterprises to
+  set up a special work user profile using the Managed Profile API. This
+  user profile is called a <em>managed profile</em>, or a <em>work profile</em>
+  in the Android for Work program. If a device has a
+  managed profile for work, the profile's settings are under the control of the
+  enterprise administrator. The administrator can choose which apps are allowed
+  for that profile, and can control just what device features are available to
+  the profile.
+</p>
+
+<h2 id="create_profile">Create a Managed Profile</h2>
+
+<p>To create a managed profile on a device that already has a personal profile,
+first check that the device can support a managed profile, by seeing if the
+device supports the {@link
+android.content.pm.PackageManager#FEATURE_MANAGED_USERS FEATURE_MANAGED_USERS}
+system feature:</p>
+
+<pre>PackageManager pm = getPackageManager();
+if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
+
+    // This device does not support native managed profiles!
+
+}</pre>
+
+<p>If the device supports managed profiles, create one by sending an intent with
+an {@link android.app.admin.DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE
+ACTION_PROVISION_MANAGED_PROFILE} action. Include the device admin package
+name as an extra.</p>
+
+<pre>Activity provisioningActivity = getActivity();
+
+// You'll need the package name for the WPC app.
+String myWPCPackageName = "com.example.myWPCApp";
+
+// Set up the provisioning intent
+Intent provisioningIntent =
+        new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
+intent.putExtra(myWPCPackageName,
+        provisioningActivity.getApplicationContext().getPackageName());
+
+if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
+         == null) {
+
+    // No handler for intent! Can't provision this device.
+    // Show an error message and cancel.
+} else {
+
+    // REQUEST_PROVISION_MANAGED_PROFILE is defined
+    // to be a suitable request code
+    startActivityForResult(provisioningIntent,
+            REQUEST_PROVISION_MANAGED_PROFILE);
+    provisioningActivity.finish();
+}</pre>
+
+<p>The system responds to this intent by doing the following:</p>
+
+<ul>
+  <li>Verifies that the device is encrypted. If it is not, the system prompts
+  the user to encrypt the device before proceeding.
+  </li>
+
+  <li>Creates a managed profile.
+  </li>
+
+  <li>Removes non-required applications from the managed profile.
+  </li>
+
+  <li>Copies the Work Policy Controller application into the managed profile and
+    sets it as the profile owner.
+  </li>
+</ul>
+
+<p>Override {@link android.app.Activity#onActivityResult onActivityResult()} to
+see whether the provisioning was successful, as shown in the following 
+example code:</p>
+
+<pre>&#64;Override
+public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+    // Check if this is the result of the provisioning activity
+    if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+
+        // If provisioning was successful, the result code is 
+        // Activity.RESULT_OK
+        if (resultCode == Activity.RESULT_OK) {
+            // Hurray! Managed profile created and provisioned!
+        } else {
+            // Boo! Provisioning failed!
+        }
+        return;
+
+    } else {
+        // This is the result of some other activity, call the superclass
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+}</pre>
+
+<h3 id="after_creating_profile">After Creating the Managed Profile</h3>
+
+<p>When the profile has been provisioned, the system calls the Work Policy
+Controller app's {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} method. Override this
+callback method to finish enabling the managed profile.</p>
+
+<p>Typically, your {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} callback implementation
+would perform these tasks:</p>
+
+<ul>
+  <li>Verify that the device is complying with the EMM's device policies, as
+  described in <a href="#set_up_policies">Set Up Device Policies</a>
+  </li>
+
+  <li>Enable any system applications that the administrator chooses to make
+  available within the managed profile, using {@link
+  android.app.admin.DevicePolicyManager#enableSystemApp
+  DevicePolicyManager.enableSystemApp()}   </li>
+
+  <li>If the device uses Google Play for Work, add the Google account
+  to the managed profile with {@link android.accounts.AccountManager#addAccount
+  AccountManager.addAccount()}, so administrators can install
+  applications to the device
+  </li>
+</ul>
+
+<p>Once you have completed these tasks, call the device policy manager's
+{@link android.app.admin.DevicePolicyManager#setProfileEnabled
+setProfileEnabled()} method to activate the managed profile:</p>
+
+
+<pre>// Get the device policy manager
+DevicePolicyManager myDevicePolicyMgr =
+        (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
+
+// Set the name for the newly created managed profile.
+myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
+
+// ...and enable the profile
+manager.setProfileEnabled(componentName);</pre>
+
+<h2 id="set_up_policies">Set Up Device Policies</h2>
+
+<p>
+  The Work Policy Controller app is responsible for applying the enterprise's
+  device policies. For example, a particular enterprise might require that all
+  devices become locked after a certain number of failed attempts to enter the
+  device password. The controller app queries the EMM to find out what
+  the current policies are, then uses the <a href=
+  "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
+  API to apply those policies.
+</p>
+
+<p>For information on how to apply device policies, see the 
+<a href="{@docRoot}guide/topics/admin/device-admin.html#policies">Device
+Administration</a> guide.</p>
+
+
+<h2 id="apply_restrictions">Apply App Restrictions</h2>
+
+<p>Enterprise environments may require that approved apps implement apps
+implement security or feature restrictions. App developers must implement these
+restrictions and declare them for use by enterprise administrators, as described
+in <a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
+App Restrictions</a>. The Work Policy Controller receives restriction changes
+from the enterprise administrator, and forwards those restriction changes to the
+apps.</p>
+
+<p>For example, a particular news app might have a restriction setting that
+controls whether the app is allowed to download videos over a cellular
+network. When the EMM wants to disable cellular downloads, it sends a
+notification to the controller app. The controller app, in turn,
+notifies the news app that the restriction setting has changed.</p>
+
+<p class="note"><strong>Note:</strong> This document covers how the Work Policy
+Controller app changes the restriction settings for the other apps on the
+managed profile. Details on how the Work Policy Controller app communicates with
+the EMM are out of scope for this document.</p>
+
+<p>To change an app's restrictions, call the {@link
+android.app.admin.DevicePolicyManager#setApplicationRestrictions
+DevicePolicyManager.setApplicationRestrictions()} method. This method is passed
+three parameters: the controller app's {@link
+android.app.admin.DeviceAdminReceiver}, the package name of the app whose
+restrictions are being changed, and a {@link android.os.Bundle Bundle} that
+contains the restrictions you want to set.</p>
+
+<p>For example, suppose there's an app on the managed profile with the package
+name <code>"com.example.newsfetcher"</code>. This app has a single boolean
+restriction that can be configured, with the key
+<code>"downloadByCellular"</code>. If this restriction is set to
+<code>false</code>, the newsfetcher app is not allowed to download data through
+a cellular network; it must use a Wi-Fi network instead.</p>
+
+<p>
+  If your Work Policy Controller app needs to turn off cellular downloads, it
+  would first fetch the device policy service object, as described above. It
+  then assembles a restrictions bundle and passes this bundle to {@link
+  android.app.admin.DevicePolicyManager#setApplicationRestrictions
+  setApplicationRestrictions()}:
+</p>
+
+<pre>// Fetch the DevicePolicyManager
+DevicePolicyManager myDevicePolicyMgr =
+        (DevicePolicyManager) thisActivity
+                .getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+// Set up the restrictions bundle
+bundle restrictionsBundle = new Bundle();
+restrictionsBundle.putBoolean("downloadByCellular", false);
+
+// Pass the restrictions to the policy manager. Assume the WPC app
+// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
+myDevicePolicyMgr.setApplicationRestrictions(
+        myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);</pre>
+
+
+<p class="note"><strong>Note:</strong> The device policy service conveys the restrictions
+change to the app you name. However, it is up to that app to actually implement
+the restriction. For example, in this case, the app would be responsible for
+disabling its ability to use cellular networks for video downloads. Setting the
+restriction does not cause the system to enforce this restriction on the app.
+For more information, see <a href="{@docRoot}training/enterprise/app-
+restrictions.html">Implementing App Restrictions</a>.</p>
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index efc0ee3..86e91a7 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -46,9 +46,10 @@
 background as:</p>
 
 <ul>
-<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple</li>
+<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple.</li>
 <li><code>?android:attr/selectableItemBackgroundBorderless</code> for a ripple that extends beyond
-the view</li>
+the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null
+background.</li>
 </ul>
 
 <p class="note"><strong>Note:</strong> <code>selectableItemBackgroundBorderless</code> is a new
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c59d8ff..89e72f1 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1040,6 +1040,32 @@
   <!-- End: Building for Auto -->
 
 
+  <!-- Start: Building for Work -->
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>training/enterprise/index.html">
+      <span class="small">Building Apps for</span><br/>
+              Work
+      </a>
+    </div>
+    <ul>
+      <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
+        Ensuring Compatibility with Managed Profiles
+      </a>
+      </li>
+      <li><a href="<?cs var:toroot ?>training/enterprise/app-restrictions.html">
+        Implementing App Restrictions
+      </a>
+      </li>
+      <li><a href="<?cs var:toroot ?>training/enterprise/work-policy-ctrl.html">
+        Building a Work Policy Controller
+      </a>
+      </li>
+    </ul>
+  </li>
+  <!-- End: Building for Work -->
+
+
   <li class="nav-section">
     <div class="nav-section-header">
       <a href="<?cs var:toroot ?>training/best-ux.html">
@@ -1752,10 +1778,6 @@
             Enhancing Security with Device Management Policies
           </a>
           </li>
-          <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
-            Ensuring Compatibility with Managed Profiles
-          </a>
-          </li>
         </ul>
       </li>
     </ul>
@@ -1887,4 +1909,4 @@
     buildToggleLists();
     changeNavLang(getLangPref());
 //-->
-</script>
\ No newline at end of file
+</script>
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index b0cd386..97f7105 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -58,7 +58,7 @@
      * No-arg constructor used by drawable inflation.
      */
     InsetDrawable() {
-        this(new InsetState(), null);
+        this(new InsetState(null), null);
     }
 
     /**
@@ -82,7 +82,7 @@
      */
     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
             int insetBottom) {
-        this(new InsetState(), null);
+        this(new InsetState(null), null);
 
         mState.mInsetLeft = insetLeft;
         mState.mInsetTop = insetTop;
@@ -267,10 +267,6 @@
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        InsetState() {
-            this(null);
-        }
-
         InsetState(InsetState orig) {
             super(orig);
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 595061c..aeef659 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -61,7 +61,7 @@
      * Create a new rotating drawable with an empty state.
      */
     public RotateDrawable() {
-        this(null, null);
+        this(new RotateState(null), null);
     }
 
     @Override
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5dacbb5..ecb625b 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -104,6 +104,14 @@
     LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
 endif
 
+ifeq (true, $(HWUI_NULL_GPU))
+    LOCAL_SRC_FILES += \
+        tests/nullegl.cpp \
+        tests/nullgles.cpp
+
+    LOCAL_CFLAGS += -DHWUI_NULL_GPU
+endif
+
 # Defaults for ATRACE_TAG and LOG_TAG for libhwui
 LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index bd933b8..e5489a8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -107,14 +107,6 @@
         startMark = startMarkNull;
         endMark = endMarkNull;
     }
-
-    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
-        setLabel = glLabelObjectEXT;
-        getLabel = glGetObjectLabelEXT;
-    } else {
-        setLabel = setLabelNull;
-        getLabel = getLabelNull;
-    }
 }
 
 void Caches::initConstraints() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 92a87e2..8aea8ff 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -207,9 +207,6 @@
     PFNGLPUSHGROUPMARKEREXTPROC startMark;
     PFNGLPOPGROUPMARKEREXTPROC endMark;
 
-    PFNGLLABELOBJECTEXTPROC setLabel;
-    PFNGLGETOBJECTLABELEXTPROC getLabel;
-
     // TEMPORARY properties
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
@@ -244,14 +241,6 @@
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
     static void endMarkNull() { }
 
-    static void setLabelNull(GLenum type, uint object, GLsizei length,
-            const char* label) { }
-    static void getLabelNull(GLenum type, uint object, GLsizei bufferSize,
-            GLsizei* length, char* label) {
-        if (length) *length = 0;
-        if (label) *label = '\0';
-    }
-
     RenderState* mRenderState;
 
     // Used to render layers
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index c68822b..2a82216 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -55,7 +55,6 @@
     mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
     mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
     mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
-    mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
     mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
     mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
     mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 731001a..e7d317d 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -40,7 +40,6 @@
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
     inline bool hasDebugMarker() const { return mHasDebugMarker; }
-    inline bool hasDebugLabel() const { return mHasDebugLabel; }
     inline bool hasTiledRendering() const { return mHasTiledRendering; }
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
@@ -68,7 +67,6 @@
     bool mHasFramebufferFetch;
     bool mHasDiscardFramebuffer;
     bool mHasDebugMarker;
-    bool mHasDebugLabel;
     bool mHasTiledRendering;
     bool mHas1BitStencil;
     bool mHas4BitStencil;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index a69f3fb..51898d2 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -25,6 +25,8 @@
 LOCAL_MODULE_STEM_32 := hwuitest
 LOCAL_MODULE_STEM_64 := hwuitest64
 
+HWUI_NULL_GPU := false
+
 include $(LOCAL_PATH)/Android.common.mk
 
 LOCAL_SRC_FILES += \
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b61d72f..0d1e63e 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -93,16 +93,16 @@
         animation.createContent(width, height, renderer);
         endRecording(renderer, rootNode);
 
-        for (int i = 0; i < 150; i++) {
+        for (int i = 0; i < animation.getFrameCount(); i++) {
+#if !HWUI_NULL_GPU
             testContext.waitForVsync();
+#endif
 
             ATRACE_NAME("UI-Draw Frame");
             animation.doFrame(i);
             proxy->syncAndDrawFrame();
         }
 
-        sleep(5);
-
         rootNode->decStrong(nullptr);
     }
 };
diff --git a/libs/hwui/tests/nullegl.cpp b/libs/hwui/tests/nullegl.cpp
new file mode 100644
index 0000000..b6cc2f2
--- /dev/null
+++ b/libs/hwui/tests/nullegl.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static EGLDisplay gDisplay = (EGLDisplay) 1;
+
+typedef struct {
+    EGLSurface surface;
+    EGLContext context;
+} ThreadState;
+
+static pthread_key_t ThreadStateKey;
+static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;
+
+static void destroyThreadState(void* state) {
+    free(state);
+}
+
+static void makeThreadState() {
+    pthread_key_create(&ThreadStateKey, destroyThreadState);
+}
+
+ThreadState* getThreadState() {
+    ThreadState* ptr;
+    pthread_once(&ThreadStateSetupOnce, makeThreadState);
+    if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
+        ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+        ptr->context = EGL_NO_CONTEXT;
+        ptr->surface = EGL_NO_SURFACE;
+        pthread_setspecific(ThreadStateKey, ptr);
+    }
+    return ptr;
+}
+
+EGLint eglGetError(void) {
+    return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+    return gDisplay;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+    return EGL_TRUE;
+}
+
+const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+    return "";
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+               EGLConfig *configs, EGLint config_size,
+               EGLint *num_config) {
+    memset(configs, 9, sizeof(EGLConfig) * config_size);
+    *num_config = config_size;
+    return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+                  EGLNativeWindowType win,
+                  const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+                   const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+    free(surface);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+               EGLint attribute, EGLint *value) {
+    *value = 1000;
+    return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+                EGLint attribute, EGLint value) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+    return EGL_TRUE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                EGLContext share_context,
+                const EGLint *attrib_list) {
+    return (EGLContext) malloc(sizeof(void*));
+}
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+    free(ctx);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+              EGLSurface read, EGLContext ctx) {
+    ThreadState* state = getThreadState();
+    state->surface = draw;
+    state->context = ctx;
+    return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext(void) {
+    return getThreadState()->context;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+    return getThreadState()->surface;
+}
+
+EGLDisplay eglGetCurrentDisplay(void) {
+    return gDisplay;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+    return EGL_TRUE;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
+    return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
+    free(image);
+    return EGL_TRUE;
+}
+
+void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}
diff --git a/libs/hwui/tests/nullgles.cpp b/libs/hwui/tests/nullgles.cpp
new file mode 100644
index 0000000..8ca7598
--- /dev/null
+++ b/libs/hwui/tests/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright(C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+    GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+    static GLuint nextId = 0;
+    int i;
+    for(i = 0; i < n; i++) {
+        buffers[i] = ++nextId;
+    }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+    glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+    glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+    glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+    static GLuint nextProgram = 0;
+    return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+    static GLuint nextShader = 0;
+    return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_DELETE_STATUS:
+    case GL_LINK_STATUS:
+    case GL_VALIDATE_STATUS:
+        *params = GL_TRUE;
+        break;
+    case GL_INFO_LOG_LENGTH:
+        *params = 16;
+        break;
+    }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_COMPILE_STATUS:
+    case GL_DELETE_STATUS:
+        *params = GL_TRUE;
+    }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        gState.scissorEnabled = value;
+        break;
+    }
+}
+
+void glEnable(GLenum cap) {
+    setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+    setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        return gState.scissorEnabled;
+    default:
+        return GL_FALSE;
+    }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+    switch (pname) {
+    case GL_MAX_TEXTURE_SIZE:
+        *data = 2048;
+        break;
+    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *data = 4;
+        break;
+    default:
+        *data = 0;
+    }
+}
+
+const char* getString(GLenum name) {
+    switch (name) {
+    case GL_VENDOR:
+        return "android";
+    case GL_RENDERER:
+        return "null";
+    case GL_VERSION:
+        return "OpenGL ES 2.0 rev1";
+    case GL_SHADING_LANGUAGE_VERSION:
+        return "OpenGL ES GLSL ES 2.0 rev1";
+    case GL_EXTENSIONS:
+    default:
+        return "";
+    }
+}
+
+const GLubyte* glGetString(GLenum name) {
+    return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {}
+void glEndTilingQCOM(GLbitfield preserveMask) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+    return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+    return GL_FALSE;
+}
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
new file mode 100644
index 0000000..28d2e26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -0,0 +1,41 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:alpha=".3"
+    android:width="64dp" >
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.8,11.1L17.0,11.1l0.0,2.0l-1.2,0.0l4.5,4.5c1.1,-1.6 1.7,-3.5 1.7,-5.5c0.0,-5.5 -4.5,-10.0 -10.0,-10.0c-2.0,0.0 -3.9,0.6 -5.5,1.7L13.8,11.1z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.0,13.1L7.0,13.1l0.0,-2.0l4.0,0.0L4.9,5.0C3.1,6.8 2.0,9.3 2.0,12.1c0.0,5.5 4.5,10.0 10.0,10.0c2.8,0.0 5.3,-1.1 7.1,-2.9L13.0,13.1z" />
+
+    <group
+        android:pivotX="12.0"
+        android:pivotY="12.0"
+        android:rotation="45.0"
+        android:translateX="0.5"
+        android:translateY="0.5" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M-2.8,11.8l28.3,0.0l0.0,2.0l-28.3,0.0z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
new file mode 100644
index 0000000..7617ec4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64dp"
+        android:height="64dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
new file mode 100644
index 0000000..9361bc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+            android:width="17dp"
+            android:height="17dp"
+            android:viewportWidth="48.0"
+            android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 27353ff..33c1899 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,6 +40,16 @@
             android:clipChildren="false" />
     </FrameLayout>
 
+    <View
+        android:id="@+id/zen_embedded_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:visibility="gone"
+        android:layout_marginStart="@dimen/qs_panel_padding"
+        android:layout_marginEnd="@dimen/qs_panel_padding"
+        android:layout_marginBottom="@dimen/qs_panel_padding"
+        android:background="#4dffffff" />
+
     <RelativeLayout
         android:id="@+id/zen_subhead"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8a73fca..2e9e9f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -118,7 +118,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
+        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d8b6a82..1b1b525 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -430,6 +430,16 @@
     <string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
     <!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+     <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
+    <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+    <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
     <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -554,6 +564,12 @@
 
     <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
     <string name="quick_settings_airplane_mode_label">Airplane mode</string>
+    <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_label">Do not disturb</string>
+    <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_priority_label">Priority only</string>
+    <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_none_label">No interruptions</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
     <string name="quick_settings_bluetooth_label">Bluetooth</string>
     <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4dacacf..7f944f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -253,12 +253,6 @@
             @Override
             public void onStateChanged(QSTile.State state) {
                 int visibility = state.visible ? VISIBLE : GONE;
-                if (state.visible && !mGridContentVisible) {
-
-                    // We don't want to show it if the content is hidden,
-                    // then we just set it to invisible, to ensure that it gets visible again
-                    visibility = INVISIBLE;
-                }
                 setTileVisibility(r.tileView, visibility);
                 r.tileView.onStateChanged(state);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
new file mode 100644
index 0000000..79600f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Do not disturb **/
+public class DndTile extends QSTile<QSTile.BooleanState> {
+    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
+    private static final String EXTRA_VISIBLE = "visible";
+    private static final String PREF_KEY_VISIBLE = "DndTileVisible";
+
+    private final ZenModeController mController;
+    private final DndDetailAdapter mDetailAdapter;
+
+    private boolean mListening;
+    private boolean mVisible;
+    private boolean mShowingDetail;
+
+    public DndTile(Host host) {
+        super(host);
+        mController = host.getZenModeController();
+        mDetailAdapter = new DndDetailAdapter();
+        mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
+        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+    }
+
+    public static void setVisible(Context context, boolean visible) {
+        context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
+                .putExtra(DndTile.EXTRA_VISIBLE, visible));
+    }
+
+    public static boolean isVisible(Context context) {
+        return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+    }
+
+    @Override
+    public DetailAdapter getDetailAdapter() {
+        return mDetailAdapter;
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleClick() {
+        if (mState.value) {
+            mController.setZen(Global.ZEN_MODE_OFF);
+        } else {
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
+        state.value = zen != Global.ZEN_MODE_OFF;
+        state.visible = mVisible;
+        switch (zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_priority_on);
+                break;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_none_on);
+                break;
+            default:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
+                state.label = mContext.getString(R.string.quick_settings_dnd_label);
+                state.contentDescription =  mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_off);
+                break;
+        }
+        if (mShowingDetail && !state.value) {
+            showDetail(false);
+        }
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
+        } else {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
+        }
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (mListening == listening) return;
+        mListening = listening;
+        if (mListening) {
+            mController.addCallback(mZenCallback);
+        } else {
+            mController.removeCallback(mZenCallback);
+        }
+    }
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        public void onZenChanged(int zen) {
+            refreshState(zen);
+        }
+    };
+
+    private static SharedPreferences getSharedPrefs(Context context) {
+        return context.getSharedPreferences(context.getPackageName(), 0);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+            getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+            refreshState();
+        }
+    };
+
+    private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
+
+        @Override
+        public int getTitle() {
+            return R.string.quick_settings_dnd_label;
+        }
+
+        @Override
+        public Boolean getToggleState() {
+            return mState.value;
+        }
+
+        @Override
+        public Intent getSettingsIntent() {
+            return ZEN_SETTINGS;
+        }
+
+        @Override
+        public void setToggleState(boolean state) {
+            if (!state) {
+                mController.setZen(Global.ZEN_MODE_OFF);
+                showDetail(false);
+            }
+        }
+
+        @Override
+        public View createDetailView(Context context, View convertView, ViewGroup parent) {
+            final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
+                    : (ZenModePanel) LayoutInflater.from(context).inflate(
+                            R.layout.zen_mode_panel, parent, false);
+            if (convertView == null) {
+                zmp.init(mController);
+                zmp.setEmbedded(true);
+                zmp.addOnAttachStateChangeListener(this);
+            }
+            return zmp;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+            mShowingDetail = true;
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mShowingDetail = false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e8a000c..5da8457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -198,7 +199,11 @@
         int volumeIconId = 0;
         String volumeDescription = null;
 
-        if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+        if (DndTile.isVisible(mContext)) {
+            zenVisible = mZen != Global.ZEN_MODE_OFF;
+            zenIconId = R.drawable.stat_sys_dnd;
+            zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+        } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_zen_none;
             zenDescription = mContext.getString(R.string.zen_no_interruptions);
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 45a1386..954eb10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.tiles.LocationTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -256,6 +257,7 @@
         else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
         else if (tileSpec.equals("cell")) return new CellularTile(this);
         else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
+        else if (tileSpec.equals("dnd")) return new DndTile(this);
         else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
         else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
         else if (tileSpec.equals("location")) return new LocationTile(this);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 8048a48..5e3ec3f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -44,6 +44,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.ServiceMonitor;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -114,6 +115,7 @@
             if (LOGD) Log.d(TAG, "Registering volume controller");
             mAudioManager.setVolumeController(mVolumeController);
             mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+            DndTile.setVisible(mContext, false);
         } else {
             if (LOGD) Log.d(TAG, "Unregistering volume controller");
             mAudioManager.setVolumeController(null);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5726fa7..6cecc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -90,9 +90,11 @@
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
     private SegmentedButtons mZenButtons;
+    private ViewGroup mZenButtonsContainer;
     private View mZenSubhead;
     private TextView mZenSubheadCollapsed;
     private TextView mZenSubheadExpanded;
+    private View mZenEmbeddedDivider;
     private View mMoreSettings;
     private LinearLayout mZenConditions;
 
@@ -114,6 +116,7 @@
     private Condition mSessionExitCondition;
     private Condition[] mConditions;
     private Condition mTimeCondition;
+    private boolean mEmbedded;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -140,9 +143,25 @@
         pw.print("  mExpanded="); pw.println(mExpanded);
         pw.print("  mSessionZen="); pw.println(mSessionZen);
         pw.print("  mAttachedZen="); pw.println(mAttachedZen);
+        pw.print("  mEmbedded="); pw.println(mEmbedded);
         mTransitionHelper.dump(fd, pw, args);
     }
 
+    public void setEmbedded(boolean embedded) {
+        if (mEmbedded == embedded) return;
+        mEmbedded = embedded;
+        mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+        if (mEmbedded) {
+            mZenButtonsContainer.setBackground(null);
+        } else {
+            mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
+        }
+        mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+        mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
+        setExpanded(mEmbedded);
+        updateWidgets();
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -156,10 +175,11 @@
                 Global.ZEN_MODE_OFF);
         mZenButtons.setCallback(mZenButtonsCallback);
 
-        final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
-        zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+        mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+        mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
 
         mZenSubhead = findViewById(R.id.zen_subhead);
+        mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
 
         mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
         mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
@@ -222,7 +242,9 @@
         mAttachedZen = -1;
         mSessionZen = -1;
         setSessionExitCondition(null);
-        setExpanded(false);
+        if (!mEmbedded) {
+            setExpanded(false);
+        }
         setRequestingConditions(false);
         mTransitionHelper.clear();
     }
@@ -361,7 +383,7 @@
 
     private void handleUpdateZen(int zen) {
         if (mSessionZen != -1 && mSessionZen != zen) {
-            setExpanded(zen != Global.ZEN_MODE_OFF);
+            setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
             mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
@@ -403,7 +425,7 @@
         final boolean expanded = !mHidden && mExpanded;
 
         mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
-        mZenSubhead.setVisibility(!mHidden && !zenOff ? VISIBLE : GONE);
+        mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
         mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c0d2502..0cbc9d7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -479,10 +479,16 @@
 
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window, userId);
+            final boolean translucent = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                    || (!ent.array.hasValue(
+                            com.android.internal.R.styleable.Window_windowIsTranslucent)
+                            && ent.array.getBoolean(
+                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                            false));
             fullscreen = ent != null && !ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowIsFloating, false)
-                    && !ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                    && !translucent;
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index afe7d7a..473f5db 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1425,6 +1425,7 @@
 
     private void sendBroadcastToAll(Intent intent) {
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final long ident = Binder.clearCallingIdentity();
         try {
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -1434,6 +1435,7 @@
     }
 
     private void sendStickyBroadcastToAll(Intent intent) {
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final long ident = Binder.clearCallingIdentity();
         try {
             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 09dc477..5f0ad9f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -46,7 +46,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -832,6 +831,24 @@
         }
     }
 
+    private void setDisplayOffsetsInternal(int displayId, int x, int y) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            if (display.getDisplayOffsetXLocked() != x
+                    || display.getDisplayOffsetYLocked() != y) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
+                            + x + ", " + y + ")");
+                }
+                display.setDisplayOffsetsLocked(x, y);
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mDefaultViewport.valid = false;
         mExternalTouchViewport.valid = false;
@@ -1513,5 +1530,10 @@
                 float requestedRefreshRate, boolean inTraversal) {
             setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal);
         }
+
+        @Override
+        public void setDisplayOffsets(int displayId, int x, int y) {
+            setDisplayOffsetsInternal(displayId, x, y);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6c57eec..3bb7818 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -76,6 +76,10 @@
     // The pending requested refresh rate. 0 if no request is pending.
     private float mRequestedRefreshRate;
 
+    // The display offsets to apply to the display projection.
+    private int mDisplayOffsetX;
+    private int mDisplayOffsetY;
+
     // Temporary rectangle used when needed.
     private final Rect mTempLayerStackRect = new Rect();
     private final Rect mTempDisplayRect = new Rect();
@@ -313,6 +317,10 @@
         mTempDisplayRect.set(displayRectLeft, displayRectTop,
                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
 
+        mTempDisplayRect.left += mDisplayOffsetX;
+        mTempDisplayRect.right += mDisplayOffsetX;
+        mTempDisplayRect.top += mDisplayOffsetY;
+        mTempDisplayRect.bottom += mDisplayOffsetY;
         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
@@ -356,10 +364,34 @@
         return mRequestedRefreshRate;
     }
 
+    /**
+     * Gets the burn-in offset in X.
+     */
+    public int getDisplayOffsetXLocked() {
+        return mDisplayOffsetX;
+    }
+
+    /**
+     * Gets the burn-in offset in Y.
+     */
+    public int getDisplayOffsetYLocked() {
+        return mDisplayOffsetY;
+    }
+
+    /**
+     * Sets the burn-in offsets.
+     */
+    public void setDisplayOffsetsLocked(int x, int y) {
+        mDisplayOffsetX = x;
+        mDisplayOffsetY = y;
+    }
+
     public void dumpLocked(PrintWriter pw) {
         pw.println("mDisplayId=" + mDisplayId);
         pw.println("mLayerStack=" + mLayerStack);
         pw.println("mHasContent=" + mHasContent);
+        pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
+        pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
                 mPrimaryDisplayDevice.getNameLocked() : "null"));
         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
new file mode 100644
index 0000000..b8a3155
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.policy;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemClock;
+import android.view.Display;
+
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
+    private static final String TAG = "BurnInProtection";
+
+    // Default value when max burnin radius is not set.
+    public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;
+
+    private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+    private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
+
+    private static final String ACTION_BURN_IN_PROTECTION =
+            "android.internal.policy.action.BURN_IN_PROTECTION";
+
+    private static final int BURN_IN_SHIFT_STEP = 2;
+
+    private boolean mBurnInProtectionActive;
+
+    private final int mMinHorizontalBurnInOffset;
+    private final int mMaxHorizontalBurnInOffset;
+    private final int mMinVerticalBurnInOffset;
+    private final int mMaxVerticalBurnInOffset;
+
+    private final int mBurnInRadiusMaxSquared;
+
+    private int mLastBurnInXOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mXOffsetDirection = 1;
+    private int mLastBurnInYOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mYOffsetDirection = 1;
+
+    private final AlarmManager mAlarmManager;
+    private final PendingIntent mBurnInProtectionIntent;
+    private final DisplayManagerInternal mDisplayManagerInternal;
+    private final Display mDisplay;
+
+    private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateBurnInProtection();
+        }
+    };
+
+    public BurnInProtectionHelper(Context context) {
+        final Resources resources = context.getResources();
+        mMinHorizontalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+        mMaxHorizontalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+        mMinVerticalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+        mMaxVerticalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+        int burnInRadiusMax = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+        if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
+            mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
+        } else {
+            mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
+        }
+
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        context.registerReceiver(mBurnInProtectionReceiver,
+                new IntentFilter(ACTION_BURN_IN_PROTECTION));
+        Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
+        intent.setPackage(context.getPackageName());
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
+                intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        DisplayManager displayManager =
+                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        displayManager.registerDisplayListener(this, null /* handler */);
+    }
+
+    public void startBurnInProtection() {
+        if (!mBurnInProtectionActive) {
+            mBurnInProtectionActive = true;
+            updateBurnInProtection();
+        }
+    }
+
+    private void updateBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            adjustOffsets();
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
+                    mLastBurnInXOffset, mLastBurnInYOffset);
+            // Next adjustment at least ten seconds in the future.
+            long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+            // And aligned to the minute.
+            next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+                    + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+        } else {
+            mAlarmManager.cancel(mBurnInProtectionIntent);
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
+        }
+    }
+
+    public void cancelBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            mBurnInProtectionActive = false;
+            updateBurnInProtection();
+        }
+    }
+
+    /**
+     * Gently shifts current burn-in offsets, minimizing the change for the user.
+     *
+     * Shifts are applied in following fashion:
+     * 1) shift horizontally from minimum to the maximum;
+     * 2) shift vertically by one from minimum to the maximum;
+     * 3) shift horizontally from maximum to the minimum;
+     * 4) shift vertically by one from minimum to the maximum.
+     * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
+     *
+     * On top of that, stay within specified radius. If the shift distance from the center is
+     * higher than the radius, skip these values and go the next position that is within the radius.
+     */
+    private void adjustOffsets() {
+        do {
+            // By default, let's just shift the X offset.
+            final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
+            mLastBurnInXOffset += xChange;
+            if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
+                    || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
+                // Whoops, we went too far horizontally. Let's retract..
+                mLastBurnInXOffset -= xChange;
+                // change horizontal direction..
+                mXOffsetDirection *= -1;
+                // and let's shift the Y offset.
+                final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
+                mLastBurnInYOffset += yChange;
+                if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
+                        || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
+                    // Whoops, we went to far vertically. Let's retract..
+                    mLastBurnInYOffset -= yChange;
+                    // and change vertical direction.
+                    mYOffsetDirection *= -1;
+                }
+            }
+            // If we are outside of the radius, let's try again.
+        } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
+                && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
+                        > mBurnInRadiusMaxSquared);
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + TAG);
+        prefix += "  ";
+        pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
+        pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
+                + mMaxHorizontalBurnInOffset + ")");
+        pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
+                + mMaxVerticalBurnInOffset + ")");
+        pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
+        pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
+                + mLastBurnInYOffset + ")");
+        pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
+                + mYOffsetDirection + ")");
+    }
+
+    @Override
+    public void onDisplayAdded(int i) {
+    }
+
+    @Override
+    public void onDisplayRemoved(int i) {
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        if (displayId == mDisplay.getDisplayId()) {
+            if (mDisplay.getState() == Display.STATE_DOZE
+                    || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+                startBurnInProtection();
+            } else {
+                cancelBurnInProtection();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f691b4e..c414072 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2006 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.
@@ -256,6 +257,7 @@
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
     SearchManager mSearchManager;
     AccessibilityManager mAccessibilityManager;
+    BurnInProtectionHelper mBurnInProtectionHelper;
 
     // Vibrator pattern for haptic feedback of a long press.
     long[] mLongPressVibePattern;
@@ -1185,6 +1187,10 @@
         mWindowManagerFuncs = windowManagerFuncs;
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+        if (context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableBurnInProtection)){
+            mBurnInProtectionHelper = new BurnInProtectionHelper(context);
+        }
 
         mHandler = new PolicyHandler();
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
@@ -6457,5 +6463,8 @@
         if (mOrientationListener != null) {
             mOrientationListener.dump(pw, prefix);
         }
+        if (mBurnInProtectionHelper != null) {
+            mBurnInProtectionHelper.dump(prefix, pw);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 62f2b48..5e4bd8b 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -93,7 +93,9 @@
         }
         c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
         mSurfaceControl.setPosition(0, 0);
-        mOverlay.setBounds(0, 0, mScreenSize.x, mScreenSize.y);
+        // Always draw the overlay with square dimensions
+        int size = Math.max(mScreenSize.x, mScreenSize.y);
+        mOverlay.setBounds(0, 0, size, size);
         mOverlay.draw(c);
         mSurface.unlockCanvasAndPost(c);
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fde0bd5..7e69e87 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4316,8 +4316,13 @@
                         + " ShowWallpaper="
                         + ent.array.getBoolean(
                                 com.android.internal.R.styleable.Window_windowShowWallpaper, false));
-                if (ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+                final boolean windowIsTranslucentDefined = ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent);
+                final boolean windowIsTranslucent = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                final boolean windowSwipeToDismiss = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+                if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
                     return;
                 }
                 if (ent.array.getBoolean(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 770da5b..6dc54ce 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4053,16 +4053,18 @@
     }
 
     /**
-     * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in
-     * which case we allow it if no account is associated with the device.
+     * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
+     * we also allow it if no accounts or additional users are present on the device.
      */
     private boolean allowedToSetDeviceOwnerOnDevice() {
-        int callingId = Binder.getCallingUid();
-        if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
-            return AccountManager.get(mContext).getAccounts().length == 0;
-        } else {
-            return !hasUserSetupCompleted(UserHandle.USER_OWNER);
+        if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+            return true;
         }
+
+        int callingId = Binder.getCallingUid();
+        return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
+                && mUserManager.getUserCount() == 1
+                && AccountManager.get(mContext).getAccounts().length == 0;
     }
 
     private void enforceCrossUserPermission(int userHandle) {
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 8af4f50..5c6d870 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -132,10 +132,14 @@
 
         if "extends" in raw:
             self.extends = raw[raw.index("extends")+1]
+            self.extends_path = self.extends.split(".")
         else:
             self.extends = None
+            self.extends_path = []
 
         self.fullname = self.pkg.name + "." + self.fullname
+        self.fullname_path = self.fullname.split(".")
+
         self.name = self.fullname[self.fullname.rindex(".")+1:]
 
     def __repr__(self):
@@ -150,6 +154,7 @@
 
         raw = raw.split()
         self.name = raw[raw.index("package")+1]
+        self.name_path = self.name.split(".")
 
     def __repr__(self):
         return self.raw
@@ -760,7 +765,7 @@
     if not clazz.name.endswith("Manager"): return
 
     for c in clazz.ctors:
-        error(clazz, c, None, "Managers must always be obtained from Context")
+        error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
 
 
 def verify_boxed(clazz):
@@ -846,35 +851,26 @@
     """Verifies that methods adding listener/callback have overload
     for specifying delivery thread."""
 
-    # Ignore UI components which deliver things on main thread
+    # Ignore UI packages which assume main thread
     skip = [
-        "android.animation",
-        "android.view",
-        "android.graphics",
-        "android.transition",
-        "android.widget",
-        "android.webkit",
+        "animation",
+        "view",
+        "graphics",
+        "transition",
+        "widget",
+        "webkit",
     ]
     for s in skip:
-        if clazz.fullname.startswith(s): return
-        if clazz.extends and clazz.extends.startswith(s): return
+        if s in clazz.pkg.name_path: return
+        if s in clazz.extends_path: return
 
-    skip = [
-        "android.app.ActionBar",
-        "android.app.AlertDialog",
-        "android.app.AlertDialog.Builder",
-        "android.app.Application",
-        "android.app.Activity",
-        "android.app.Dialog",
-        "android.app.Fragment",
-        "android.app.FragmentManager",
-        "android.app.LoaderManager",
-        "android.app.ListActivity",
-        "android.app.AlertDialog.Builder"
-        "android.content.Loader",
-    ]
-    for s in skip:
-        if clazz.fullname == s or clazz.extends == s: return
+    # Ignore UI classes which assume main thread
+    if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+        for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+            if s in clazz.fullname: return
+    if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+        for s in ["Loader"]:
+            if s in clazz.fullname: return
 
     found = {}
     by_name = collections.defaultdict(list)