Merge "Remove some overdraw in Keyguard" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 0d1cee4..48e34d7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5499,7 +5499,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
-    field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+    field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
@@ -5512,7 +5512,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
diff --git a/api/removed.txt b/api/removed.txt
index 3c16276..c8a3b4b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -22,14 +22,6 @@
 
 }
 
-package android.service.notification {
-
-  public static class NotificationListenerService.Ranking {
-    method public boolean meetsInterruptionFilter();
-  }
-
-}
-
 package android.view {
 
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index f4e4671..25417ed 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -92,21 +92,27 @@
      */
     public static Animator loadAnimator(Resources resources, Theme theme, int id)
             throws NotFoundException {
+        return loadAnimator(resources, theme, id, 1);
+    }
+
+    /** @hide */
+    public static Animator loadAnimator(Resources resources, Theme theme, int id,
+            float pathErrorScale) throws NotFoundException {
 
         XmlResourceParser parser = null;
         try {
             parser = resources.getAnimation(id);
-            return createAnimatorFromXml(resources, theme, parser);
+            return createAnimatorFromXml(resources, theme, parser, pathErrorScale);
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException("Can't load animation resource ID #0x" +
-                    Integer.toHexString(id));
+                            Integer.toHexString(id));
             rnf.initCause(ex);
             throw rnf;
         } catch (IOException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException("Can't load animation resource ID #0x" +
-                    Integer.toHexString(id));
+                            Integer.toHexString(id));
             rnf.initCause(ex);
             throw rnf;
         } finally {
@@ -177,7 +183,7 @@
                         }
                         if (animator == null) {
                             animator = createAnimatorFromXml(context.getResources(),
-                                    context.getTheme(), parser);
+                                    context.getTheme(), parser, 1f);
                         }
 
                         if (animator == null) {
@@ -248,9 +254,11 @@
      * @param arrayAnimator Incoming typed array for Animator's attributes.
      * @param arrayObjectAnimator Incoming typed array for Object Animator's
      *            attributes.
+     * @param pixelSize The relative pixel size, used to calculate the
+     *                  maximum error for path animations.
      */
     private static void parseAnimatorFromTypeArray(ValueAnimator anim,
-            TypedArray arrayAnimator, TypedArray arrayObjectAnimator) {
+            TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) {
         long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300);
 
         long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
@@ -303,7 +311,7 @@
         }
 
         if (arrayObjectAnimator != null) {
-            setupObjectAnimator(anim, arrayObjectAnimator, getFloats);
+            setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize);
         }
     }
 
@@ -351,9 +359,11 @@
      * @param anim The target Animator which will be updated.
      * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
      * @param getFloats True if the value type is float.
+     * @param pixelSize The relative pixel size, used to calculate the
+     *                  maximum error for path animations.
      */
     private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
-            boolean getFloats) {
+            boolean getFloats, float pixelSize) {
         ObjectAnimator oa = (ObjectAnimator) anim;
         String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
 
@@ -370,7 +380,8 @@
                         + " propertyXName or propertyYName is needed for PathData");
             } else {
                 Path path = PathParser.createPathFromPathData(pathData);
-                PathKeyframes keyframeSet = KeyframeSet.ofPath(path);
+                float error = 0.5f * pixelSize; // max half a pixel error
+                PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
                 Keyframes xKeyframes;
                 Keyframes yKeyframes;
                 if (getFloats) {
@@ -487,13 +498,15 @@
         }
     }
 
-    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
+            float pixelSize)
             throws XmlPullParserException, IOException {
-        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
+        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0,
+                pixelSize);
     }
 
     private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
-            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
+            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
             throws XmlPullParserException, IOException {
 
         Animator anim = null;
@@ -513,9 +526,9 @@
             String name = parser.getName();
 
             if (name.equals("objectAnimator")) {
-                anim = loadObjectAnimator(res, theme, attrs);
+                anim = loadObjectAnimator(res, theme, attrs, pixelSize);
             } else if (name.equals("animator")) {
-                anim = loadAnimator(res, theme, attrs, null);
+                anim = loadAnimator(res, theme, attrs, null, pixelSize);
             } else if (name.equals("set")) {
                 anim = new AnimatorSet();
                 TypedArray a;
@@ -526,7 +539,8 @@
                 }
                 int ordering = a.getInt(R.styleable.AnimatorSet_ordering,
                         TOGETHER);
-                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
+                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
+                        pixelSize);
                 a.recycle();
             } else {
                 throw new RuntimeException("Unknown animator name: " + parser.getName());
@@ -556,11 +570,11 @@
 
     }
 
-    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
-            throws NotFoundException {
+    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
+            float pathErrorScale) throws NotFoundException {
         ObjectAnimator anim = new ObjectAnimator();
 
-        loadAnimator(res, theme, attrs, anim);
+        loadAnimator(res, theme, attrs, anim, pathErrorScale);
 
         return anim;
     }
@@ -575,7 +589,7 @@
      *            ObjectAnimator
      */
     private static ValueAnimator loadAnimator(Resources res, Theme theme,
-            AttributeSet attrs, ValueAnimator anim)
+            AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
             throws NotFoundException {
 
         TypedArray arrayAnimator = null;
@@ -601,7 +615,7 @@
             anim = new ValueAnimator();
         }
 
-        parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator);
+        parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
 
         final int resID =
                 arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index fc9bbb1..8d15db2 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -154,6 +154,10 @@
         return new PathKeyframes(path);
     }
 
+    public static PathKeyframes ofPath(Path path, float error) {
+        return new PathKeyframes(path, error);
+    }
+
     /**
      * Sets the TypeEvaluator to be used when calculating animated values. This object
      * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9f49194..43fa3f0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -599,17 +599,18 @@
                 mOriginalAlphas.put(view, view.getAlpha());
             }
             view.setAlpha(0f);
-            view.setTransitionAlpha(0f);
         }
     }
 
-    protected void showViews(ArrayList<View> views) {
+    protected void showViews(ArrayList<View> views, boolean setTransitionAlpha) {
         int count = views.size();
         for (int i = 0; i < count; i++) {
             View view = views.get(i);
             Float alpha = mOriginalAlphas.remove(view);
             if (alpha != null) {
                 view.setAlpha(alpha);
+            }
+            if (setTransitionAlpha) {
                 view.setTransitionAlpha(1f);
             }
         }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f38c108..9c7728e 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -240,7 +240,7 @@
         if (!mIsCanceled) {
             mIsCanceled = true;
             if (getViewsTransition() == null || mIsViewsTransitionStarted) {
-                showViews(mSharedElements);
+                showViews(mSharedElements, true);
             } else {
                 mTransitioningViews.addAll(mSharedElements);
             }
@@ -300,7 +300,7 @@
         // Now start shared element transition
         ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
                 mSharedElementNames);
-        showViews(mSharedElements);
+        showViews(mSharedElements, true);
         scheduleSetSharedElementEnd(sharedElementSnapshots);
         ArrayList<SharedElementOriginalState> originalImageViewState =
                 setSharedElementState(sharedElementState, sharedElementSnapshots);
@@ -411,7 +411,7 @@
                     @Override
                     public void onTransitionStart(Transition transition) {
                         mEnterViewsTransition = transition;
-                        showViews(mTransitioningViews);
+                        showViews(mTransitioningViews, false);
                         super.onTransitionStart(transition);
                     }
 
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 982bbc4..e85ec63 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -126,8 +126,8 @@
     }
 
     public void resetViews() {
-        showViews(mTransitioningViews);
-        showViews(mSharedElements);
+        showViews(mTransitioningViews, true);
+        showViews(mSharedElements, true);
         mIsHidden = true;
         if (!mIsReturning && getDecor() != null) {
             getDecor().suppressLayout(false);
@@ -296,7 +296,7 @@
                     transition.removeListener(this);
                     exitTransitionComplete();
                     if (mIsHidden) {
-                        showViews(mTransitioningViews);
+                        showViews(mTransitioningViews, true);
                     }
                     if (mSharedElementBundle != null) {
                         delayCancel();
@@ -323,7 +323,7 @@
                     transition.removeListener(this);
                     sharedElementTransitionComplete();
                     if (mIsHidden) {
-                        showViews(mSharedElements);
+                        showViews(mSharedElements, true);
                     }
                 }
             });
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2476c4b..f9e4895 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -842,6 +842,13 @@
     public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
 
     /**
+     * {@link #extras} key: the user that built the notification.
+     *
+     * @hide
+     */
+    public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
+
+    /**
      * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
      * displayed in the heads up space.
      *
@@ -1880,6 +1887,11 @@
         private int mColor = COLOR_DEFAULT;
 
         /**
+         * The user that built the notification originally.
+         */
+        private int mOriginatingUserId;
+
+        /**
          * Contains extras related to rebuilding during the build phase.
          */
         private Bundle mRebuildBundle = new Bundle();
@@ -2599,7 +2611,7 @@
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
             return mContext.getPackageManager().getUserBadgeForDensity(
-                    new UserHandle(mContext.getUserId()), 0);
+                    new UserHandle(mOriginatingUserId), 0);
         }
 
         private Bitmap getProfileBadge() {
@@ -2739,9 +2751,9 @@
             } else {
                 contentView.setViewVisibility(R.id.text2, View.GONE);
                 if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) {
+                    contentView.setViewVisibility(R.id.progress, View.VISIBLE);
                     contentView.setProgressBar(
                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
-                    contentView.setViewVisibility(R.id.progress, View.VISIBLE);
                     showLine2 = true;
                 } else {
                     contentView.setViewVisibility(R.id.progress, View.GONE);
@@ -3070,6 +3082,7 @@
          */
         public void populateExtras(Bundle extras) {
             // Store original information used in the construction of this object
+            extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
             extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO,
                     mContext.getApplicationInfo());
             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
@@ -3301,6 +3314,7 @@
 
             // Extras.
             Bundle extras = n.extras;
+            mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID);
             mContentTitle = extras.getCharSequence(EXTRA_TITLE);
             mContentText = extras.getCharSequence(EXTRA_TEXT);
             mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
@@ -3333,6 +3347,7 @@
          * object.
          */
         public Notification build() {
+            mOriginatingUserId = mContext.getUserId();
             mHasThreeLines = hasThreeLines();
 
             Notification n = buildUnstyled();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5b02313..ea041e8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -111,7 +111,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_PROFILE
-        = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+        = "android.app.action.PROVISION_MANAGED_PROFILE";
 
     /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows
@@ -138,7 +138,7 @@
      * message containing an Nfc record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
-        = "android.app.extra.deviceAdminPackageName";
+        = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
 
     /**
      * A String extra that, holds the email address of the account which a managed profile is
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e6ff17b..e6da670 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -374,6 +374,9 @@
             }
 
             mIntermediateBufferSize = bestPreviewDimen;
+            mParams.setPreviewSize(mIntermediateBufferSize.getWidth(),
+                    mIntermediateBufferSize.getHeight());
+
             if (DEBUG) {
                 Log.d(TAG, "Intermediate buffer selected with dimens: " +
                         bestPreviewDimen.toString());
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f4c2dc8..01fda47 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3739,6 +3739,13 @@
                 "show_note_about_notification_hiding";
 
         /**
+         * Set to 1 by the system after trust agents have been initialized.
+         * @hide
+         */
+        public static final String TRUST_AGENTS_INITIALIZED =
+                "trust_agents_initialized";
+
+        /**
          * The Logging ID (a unique 64-bit value) as a hex string.
          * Used as a pseudonymous identifier for logging.
          * @deprecated This identifier is poorly initialized and has
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index aa724f0..3a91d1a 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Parcel;
@@ -28,6 +29,7 @@
  *
  * @hide
  */
+@SystemApi
 public class Condition implements Parcelable {
 
     public static final String SCHEME = "condition";
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 326412f..03ee726 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -17,6 +17,7 @@
 package android.service.notification;
 
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.app.INotificationManager;
 import android.app.Service;
 import android.content.Context;
@@ -44,6 +45,7 @@
  *
  * @hide
  */
+@SystemApi
 public abstract class ConditionProviderService extends Service {
     private final String TAG = ConditionProviderService.class.getSimpleName()
             + "[" + getClass().getSimpleName() + "]";
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d744070..b22fd9c 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -756,15 +756,6 @@
             return mVisibilityOverride;
         }
 
-        /**
-         * Returns whether the notification meets the user's interruption
-         * filter.
-         *
-         * @removed
-         */
-        public boolean meetsInterruptionFilter() {
-            return mMatchesInterruptionFilter;
-        }
 
         /**
          * Returns whether the notification matches the user's interruption
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 872f911..9cbedab 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -17,6 +17,7 @@
 package android.service.notification;
 
 import android.content.ComponentName;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -55,6 +56,11 @@
     public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
             Calendar.WEDNESDAY, Calendar.THURSDAY };
 
+    public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+    private static final int SECONDS_MS = 1000;
+    private static final int MINUTES_MS = 60 * SECONDS_MS;
+    private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
+
     private static final int XML_VERSION = 1;
     private static final String ZEN_TAG = "zen";
     private static final String ZEN_ATT_VERSION = "version";
@@ -445,6 +451,23 @@
         return downtime;
     }
 
+    public static Condition toTimeCondition(int minutesFromNow) {
+        final long now = System.currentTimeMillis();
+        final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
+        return toTimeCondition(now + millis, minutesFromNow);
+    }
+
+    public static Condition toTimeCondition(long time, int minutes) {
+        final int num = minutes < 60 ? minutes : Math.round(minutes / 60f);
+        final int resId = minutes < 60
+                ? com.android.internal.R.plurals.zen_mode_duration_minutes
+                : com.android.internal.R.plurals.zen_mode_duration_hours;
+        final String caption = Resources.getSystem().getQuantityString(resId, num, num);
+        final Uri id = toCountdownConditionId(time);
+        return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
     // For built-in conditions
     private static final String SYSTEM_AUTHORITY = "android";
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8a1d5af..bf2d09b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2773,7 +2773,7 @@
         android:description="@string/permdesc_bindNotificationListenerService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by an {@link
+    <!-- @SystemApi Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
          @hide -->
diff --git a/core/res/res/layout/notification_template_part_line2.xml b/core/res/res/layout/notification_template_part_line2.xml
index 7e99c5e..aeef3ab 100644
--- a/core/res/res/layout/notification_template_part_line2.xml
+++ b/core/res/res/layout/notification_template_part_line2.xml
@@ -45,13 +45,13 @@
             android:visibility="gone"
             />
     </LinearLayout>
-    <ProgressBar
+    <ViewStub
         android:id="@android:id/progress"
+        android:layout="@layout/notification_template_progressbar"
         android:layout_width="match_parent"
         android:layout_height="15dp"
         android:layout_marginEnd="8dp"
         android:visibility="gone"
         android:layout_weight="0"
-        style="@style/Widget.Material.Light.ProgressBar.Horizontal"
         />
 </merge>
diff --git a/core/res/res/layout/notification_template_progressbar.xml b/core/res/res/layout/notification_template_progressbar.xml
new file mode 100644
index 0000000..61480b8
--- /dev/null
+++ b/core/res/res/layout/notification_template_progressbar.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/progress"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+    />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5c932fd..50da1fa 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4877,4 +4877,19 @@
 
     <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
     <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10.00 PM">%1$s</xliff:g></string>
+
+    <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_minutes">
+        <item quantity="one">For one minute</item>
+        <item quantity="other">For %d minutes</item>
+    </plurals>
+
+    <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_hours">
+        <item quantity="one">For one hour</item>
+        <item quantity="other">For %d hours</item>
+    </plurals>
+
+    <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_forever">Indefinitely</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c28f3a6..556c07f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1918,6 +1918,9 @@
   <java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
   <java-symbol type="string" name="battery_saver_description" />
   <java-symbol type="string" name="downtime_condition_summary" />
+  <java-symbol type="string" name="zen_mode_forever" />
+  <java-symbol type="plurals" name="zen_mode_duration_minutes" />
+  <java-symbol type="plurals" name="zen_mode_duration_hours" />
 
   <java-symbol type="string" name="item_is_selected" />
   <java-symbol type="string" name="day_of_week_label_typeface" />
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index ba22550..e5e2f18 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -252,6 +252,7 @@
             throws XmlPullParserException, IOException {
 
         int eventType = parser.getEventType();
+        float pathErrorScale = 1;
         while (eventType != XmlPullParser.END_DOCUMENT) {
             if (eventType == XmlPullParser.START_TAG) {
                 final String tagName = parser.getName();
@@ -261,9 +262,11 @@
                     int drawableRes = a.getResourceId(
                             R.styleable.AnimatedVectorDrawable_drawable, 0);
                     if (drawableRes != 0) {
-                        mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+                        VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable(
                                 drawableRes, theme).mutate();
-                        mAnimatedVectorState.mVectorDrawable.setAllowCaching(false);
+                        vectorDrawable.setAllowCaching(false);
+                        pathErrorScale = vectorDrawable.getPixelSize();
+                        mAnimatedVectorState.mVectorDrawable = vectorDrawable;
                     }
                     a.recycle();
                 } else if (TARGET.equals(tagName)) {
@@ -275,7 +278,8 @@
                     int id = a.getResourceId(
                             R.styleable.AnimatedVectorDrawableTarget_animation, 0);
                     if (id != 0) {
-                        Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+                        Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id,
+                                pathErrorScale);
                         setupAnimatorsForTarget(target, objectAnimator);
                     }
                     a.recycle();
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 042da5b..a07ccc4 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -368,6 +368,29 @@
         }
     }
 
+    /**
+     * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension.
+     * This is used to calculate the path animation accuracy.
+     *
+     * @hide
+     */
+    public float getPixelSize() {
+        if (mVectorState == null && mVectorState.mVPathRenderer == null ||
+                mVectorState.mVPathRenderer.mBaseWidth == 0 ||
+                mVectorState.mVPathRenderer.mBaseHeight == 0 ||
+                mVectorState.mVPathRenderer.mViewportHeight == 0 ||
+                mVectorState.mVPathRenderer.mViewportWidth == 0) {
+            return 1; // fall back to 1:1 pixel mapping.
+        }
+        float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
+        float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
+        float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
+        float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+        float scaleX = viewportWidth / intrinsicWidth;
+        float scaleY = viewportHeight / intrinsicHeight;
+        return Math.min(scaleX, scaleY);
+    }
+
     /** @hide */
     public static VectorDrawable create(Resources resources, int rid) {
         try {
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
index 2d20b02..d539856 100644
--- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -152,6 +152,11 @@
         mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
         if (mEnableHaptics) {
diff --git a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
index f3ba3a7..6497f46 100644
--- a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
@@ -145,6 +145,11 @@
         }
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     private Rect getCharBounds() {
         float textHeight = mTextHeightRaw * getResources().getDisplayMetrics().scaledDensity;
         mDrawPaint.setTextSize(textHeight);
diff --git a/packages/SystemUI/res/layout/notification_public_default.xml b/packages/SystemUI/res/layout/notification_public_default.xml
new file mode 100644
index 0000000..acfc4bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_public_default.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="64dp"
+    internal:layout_minHeight="64dp"
+    internal:layout_maxHeight="64dp"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_marginTop="12dp"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="12dp"
+        android:scaleType="centerInside"
+        />
+    <DateTimeView android:id="@+id/time"
+        android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_alignParentEnd="true"
+        android:layout_alignBaseline="@id/title"
+        android:singleLine="true"
+        android:gravity="center"
+        android:paddingStart="8dp"
+        android:visibility="gone"
+        />
+    <TextView android:id="@+id/title"
+        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_toEndOf="@id/icon"
+        android:layout_toStartOf="@id/time"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"
+        />
+    <ImageView android:id="@+id/profile_badge_line3"
+        android:layout_width="@*android:dimen/notification_badge_size"
+        android:layout_height="@*android:dimen/notification_badge_size"
+        android:layout_below="@id/title"
+        android:layout_marginStart="4dp"
+        android:layout_marginEnd="8dp"
+        android:layout_alignParentEnd="true"
+        android:scaleType="fitCenter"
+        android:visibility="gone"
+        />
+    <TextView android:id="@+id/text"
+        android:textAppearance="@android:style/TextAppearance.Material.Notification"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignStart="@id/title"
+        android:layout_below="@id/title"
+        android:layout_toStartOf="@id/profile_badge_line3"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"
+        />
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 5cdf819..2eb99ba 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -40,7 +40,6 @@
                 android:layout_height="wrap_content"
                 android:layout_marginEnd="8dp"
                 android:minWidth="132dp"
-                android:text="@string/quick_settings_more_settings"
                 android:textAppearance="@style/TextAppearance.QS.DetailButton"
                 android:focusable="true" />
 
@@ -50,9 +49,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:minWidth="88dp"
-                android:text="@string/quick_settings_done"
                 android:textAppearance="@style/TextAppearance.QS.DetailButton"
                 android:focusable="true"/>
 
     </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 6b829e5..e9d86d6 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -52,9 +52,10 @@
         android:paddingStart="8dp"
         />
 
-    <include
-        layout="@layout/notification_guts"
-        android:id="@+id/notification_guts"
+    <ViewStub
+        android:layout="@layout/notification_guts"
+        android:id="@+id/notification_guts_stub"
+        android:inflatedId="@+id/notification_guts"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 147efaf..0445fe8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -736,9 +736,6 @@
     <!-- Shows when people have clicked at the right edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] -->
     <string name="camera_hint">Swipe left for camera</string>
 
-    <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever">Indefinitely</string>
-
     <!-- Interruption level: None. [CHAR LIMIT=20] -->
     <string name="interruption_level_none">None</string>
 
@@ -805,18 +802,6 @@
     <string name="user_add_user_message_short" msgid="1511354412249044381">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string>
 
 
-    <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
-    <plurals name="zen_mode_duration_minutes">
-        <item quantity="one">For one minute</item>
-        <item quantity="other">For %d minutes</item>
-    </plurals>
-
-    <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
-    <plurals name="zen_mode_duration_hours">
-        <item quantity="one">For one hour</item>
-        <item quantity="other">For %d hours</item>
-    </plurals>
-
     <!-- Battery saver notification title. [CHAR LIMIT=60]-->
     <string name="battery_saver_notification_title">Battery saver is on</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
index b86e67c..a9fdc86 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
@@ -23,7 +23,6 @@
 import android.text.TextUtils.TruncateAt;
 import android.view.Gravity;
 import android.view.View;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -41,7 +40,7 @@
  *               truncate.
  *   Second line: ellipsis if necessary
  */
-public class QSDualTileLabel extends FrameLayout {
+public class QSDualTileLabel extends LinearLayout {
 
     private final Context mContext;
     private final TextView mFirstLine;
@@ -54,6 +53,7 @@
     public QSDualTileLabel(Context context) {
         super(context);
         mContext = context;
+        setOrientation(LinearLayout.VERTICAL);
 
         mHorizontalPaddingPx = mContext.getResources()
                 .getDimensionPixelSize(R.dimen.qs_dual_tile_padding_horizontal);
@@ -70,13 +70,13 @@
         mFirstLineCaret.setScaleType(ImageView.ScaleType.MATRIX);
         mFirstLineCaret.setClickable(false);
         firstLineLayout.addView(mFirstLineCaret);
-        addView(firstLineLayout, newFrameLayoutParams());
+        addView(firstLineLayout, newLinearLayoutParams());
 
         mSecondLine = initTextView();
         mSecondLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
         mSecondLine.setEllipsize(TruncateAt.END);
         mSecondLine.setVisibility(GONE);
-        addView(mSecondLine, newFrameLayoutParams());
+        addView(mSecondLine, newLinearLayoutParams());
 
         addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
@@ -89,7 +89,7 @@
         });
     }
 
-    private static LayoutParams newFrameLayoutParams() {
+    private static LayoutParams newLinearLayoutParams() {
         final LayoutParams lp =
                 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         lp.gravity = Gravity.CENTER_HORIZONTAL;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 6bfe0a4..2fafb2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -89,6 +89,7 @@
         mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
         mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
         mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
+        updateDetailText();
         mDetail.setVisibility(GONE);
         mDetail.setClickable(true);
         mBrightnessView = LayoutInflater.from(context).inflate(
@@ -112,6 +113,11 @@
         });
     }
 
+    private void updateDetailText() {
+        mDetailDoneButton.setText(R.string.quick_settings_done);
+        mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
+    }
+
     public void setBrightnessMirror(BrightnessMirrorController c) {
         super.onFinishInflate();
         ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -150,6 +156,7 @@
         if (mListening) {
             refreshAllTiles();
         }
+        updateDetailText();
     }
 
     @Override
@@ -525,6 +532,12 @@
     };
 
     private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
+        public void onAnimationCancel(Animator animation) {
+            // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
+            // called, this will avoid accidentally turning off the grid when we don't want to.
+            animation.removeListener(this);
+        };
+
         @Override
         public void onAnimationEnd(Animator animation) {
             setGridContentVisibility(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 4d85352..907a13f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -69,6 +69,7 @@
 import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
@@ -764,17 +765,95 @@
         }, false /* afterKeyguardGone */);
     }
 
+    private void inflateGuts(ExpandableNotificationRow row) {
+        ViewStub stub = (ViewStub) row.findViewById(R.id.notification_guts_stub);
+        if (stub != null) {
+            stub.inflate();
+        }
+        final StatusBarNotification sbn = row.getStatusBarNotification();
+        PackageManager pmUser = getPackageManagerForUser(
+                sbn.getUser().getIdentifier());
+        row.setTag(sbn.getPackageName());
+        final View guts = row.findViewById(R.id.notification_guts);
+        final String pkg = sbn.getPackageName();
+        String appname = pkg;
+        Drawable pkgicon = null;
+        int appUid = -1;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                    PackageManager.GET_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+                pkgicon = pmUser.getApplicationIcon(info);
+                appUid = info.uid;
+            }
+        } catch (NameNotFoundException e) {
+            // app is gone, just show package name and generic icon
+            pkgicon = pmUser.getDefaultActivityIcon();
+        }
+        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
+        ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
+        ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
+        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        final View appSettingsButton
+                = guts.findViewById(R.id.notification_inspect_app_provided_settings);
+        if (appUid >= 0) {
+            final int appUidF = appUid;
+            settingsButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    startAppNotificationSettingsActivity(pkg, appUidF);
+                }
+            });
+
+            final Intent appSettingsQueryIntent
+                    = new Intent(Intent.ACTION_MAIN)
+                    .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+                    .setPackage(pkg);
+            List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
+            if (infos.size() > 0) {
+                appSettingsButton.setVisibility(View.VISIBLE);
+                appSettingsButton.setContentDescription(
+                        mContext.getResources().getString(
+                                R.string.status_bar_notification_app_settings_title,
+                                appname
+                        ));
+                final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
+                        .setClassName(pkg, infos.get(0).activityInfo.name);
+                appSettingsButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
+                                sbn.getId(),
+                                sbn.getTag(),
+                                appUidF);
+                    }
+                });
+            } else {
+                appSettingsButton.setVisibility(View.GONE);
+            }
+        } else {
+            settingsButton.setVisibility(View.GONE);
+            appSettingsButton.setVisibility(View.GONE);
+        }
+
+    }
+
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
         return new SwipeHelper.LongPressListener() {
             @Override
             public boolean onLongPress(View v, int x, int y) {
                 dismissPopups();
 
+                if (!(v instanceof ExpandableNotificationRow)) {
+                    return false;
+                }
                 if (v.getWindowToken() == null) {
                     Log.e(TAG, "Trying to show notification guts, but not attached to window");
                     return false;
                 }
 
+                inflateGuts((ExpandableNotificationRow) v);
+
                 // Assume we are a status_bar_notification_row
                 final NotificationGuts guts = (NotificationGuts) v.findViewById(
                         R.id.notification_guts);
@@ -1190,67 +1269,6 @@
             row.setExpansionLogger(this, entry.notification.getKey());
         }
 
-        // the notification inspector (see SwipeHelper.setLongPressListener)
-        row.setTag(sbn.getPackageName());
-        final View guts = row.findViewById(R.id.notification_guts);
-        final String pkg = entry.notification.getPackageName();
-        String appname = pkg;
-        Drawable pkgicon = null;
-        int appUid = -1;
-        try {
-            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
-                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
-            if (info != null) {
-                appname = String.valueOf(pmUser.getApplicationLabel(info));
-                pkgicon = pmUser.getApplicationIcon(info);
-                appUid = info.uid;
-            }
-        } catch (NameNotFoundException e) {
-            // app is gone, just show package name and generic icon
-            pkgicon = pmUser.getDefaultActivityIcon();
-        }
-        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
-        ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
-        ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
-        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
-        final View appSettingsButton
-                = guts.findViewById(R.id.notification_inspect_app_provided_settings);
-        if (appUid >= 0) {
-            final int appUidF = appUid;
-            settingsButton.setOnClickListener(new View.OnClickListener() {
-                public void onClick(View v) {
-                    startAppNotificationSettingsActivity(pkg, appUidF);
-                }
-            });
-
-            final Intent appSettingsQueryIntent
-                    = new Intent(Intent.ACTION_MAIN)
-                        .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
-                        .setPackage(pkg);
-            List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
-            if (infos.size() > 0) {
-                appSettingsButton.setVisibility(View.VISIBLE);
-                appSettingsButton.setContentDescription(
-                        mContext.getResources().getString(
-                                R.string.status_bar_notification_app_settings_title,
-                                appname
-                        ));
-                final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
-                        .setClassName(pkg, infos.get(0).activityInfo.name);
-                appSettingsButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
-                                sbn.getId(),
-                                sbn.getTag(),
-                                appUidF);
-                    }
-                });
-            }
-        } else {
-            settingsButton.setVisibility(View.GONE);
-            appSettingsButton.setVisibility(View.GONE);
-        }
-
         workAroundBadLayerDrawableOpacity(row);
         View vetoButton = updateNotificationVetoButton(row, sbn);
         vetoButton.setContentDescription(mContext.getString(
@@ -1331,12 +1349,12 @@
         if (publicViewLocal == null) {
             // Add a basic notification template
             publicViewLocal = LayoutInflater.from(mContext).inflate(
-                    com.android.internal.R.layout.notification_template_material_base,
+                    R.layout.notification_public_default,
                     expandedPublic, false);
             publicViewLocal.setIsRootNamespace(true);
             expandedPublic.setContractedChild(publicViewLocal);
 
-            final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
+            final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
             try {
                 title.setText(pmUser.getApplicationLabel(
                         pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
@@ -1344,10 +1362,9 @@
                 title.setText(entry.notification.getPackageName());
             }
 
-            final ImageView icon = (ImageView) publicViewLocal.findViewById(
-                    com.android.internal.R.id.icon);
+            final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
             final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
-                    com.android.internal.R.id.profile_badge_line3);
+                    R.id.profile_badge_line3);
 
             final StatusBarIcon ic = new StatusBarIcon(entry.notification.getPackageName(),
                     entry.notification.getUser(),
@@ -1383,16 +1400,13 @@
             }
 
             final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
+            final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
             if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
-                final View timeStub = publicViewLocal.findViewById(com.android.internal.R.id.time);
-                timeStub.setVisibility(View.VISIBLE);
-                final DateTimeView dateTimeView = (DateTimeView)
-                        publicViewLocal.findViewById(com.android.internal.R.id.time);
-                dateTimeView.setTime(entry.notification.getNotification().when);
+                time.setVisibility(View.VISIBLE);
+                time.setTime(entry.notification.getNotification().when);
             }
 
-            final TextView text = (TextView) publicViewLocal.findViewById(
-                com.android.internal.R.id.text);
+            final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
             if (text != null) {
                 text.setText(R.string.notification_hidden_text);
                 text.setTextAppearance(mContext,
@@ -1432,7 +1446,7 @@
             row.setUserExpanded(userExpanded);
         }
         row.setUserLocked(userLocked);
-
+        row.setStatusBarNotification(entry.notification);
         return true;
     }
 
@@ -1946,6 +1960,7 @@
         } else {
             entry.row.setOnClickListener(null);
         }
+        entry.row.setStatusBarNotification(notification);
         entry.row.notifyContentUpdated();
         entry.row.resetHeight();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index c13593a..2ad6859 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -20,9 +20,11 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
 
 import android.widget.ImageView;
@@ -67,6 +69,8 @@
     private boolean mWasReset;
     private NotificationGuts mGuts;
 
+    private StatusBarNotification mStatusBarNotification;
+
     public void setIconAnimationRunning(boolean running) {
         setIconAnimationRunning(running, mPublicLayout);
         setIconAnimationRunning(running, mPrivateLayout);
@@ -112,6 +116,14 @@
         }
     }
 
+    public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
+        mStatusBarNotification = statusBarNotification;
+    }
+
+    public StatusBarNotification getStatusBarNotification() {
+        return mStatusBarNotification;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -155,7 +167,15 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-        mGuts = (NotificationGuts) findViewById(R.id.notification_guts);
+        ViewStub gutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
+        gutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+            @Override
+            public void onInflate(ViewStub stub, View inflated) {
+                mGuts = (NotificationGuts) inflated;
+                mGuts.setClipTopAmount(getClipTopAmount());
+                mGuts.setActualHeight(getActualHeight());
+            }
+        });
         mVetoButton = findViewById(R.id.veto);
     }
 
@@ -421,7 +441,9 @@
     public void setActualHeight(int height, boolean notifyListeners) {
         mPrivateLayout.setActualHeight(height);
         mPublicLayout.setActualHeight(height);
-        mGuts.setActualHeight(height);
+        if (mGuts != null) {
+            mGuts.setActualHeight(height);
+        }
         invalidate();
         super.setActualHeight(height, notifyListeners);
     }
@@ -443,7 +465,9 @@
         super.setClipTopAmount(clipTopAmount);
         mPrivateLayout.setClipTopAmount(clipTopAmount);
         mPublicLayout.setClipTopAmount(clipTopAmount);
-        mGuts.setClipTopAmount(clipTopAmount);
+        if (mGuts != null) {
+            mGuts.setClipTopAmount(clipTopAmount);
+        }
     }
 
     public void notifyContentUpdated() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7261ea1..2f21781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -684,7 +684,7 @@
                 removeCallbacks(mPeekRunnable);
                 mPeekRunnable.run();
             }
-        } else if (!isFullyCollapsed() && !mTracking) {
+        } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
             if (mHeightAnimator != null) {
                 mHeightAnimator.cancel();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 6949ffb..fa43f32 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -431,6 +431,9 @@
 
     public void onConfigurationChanged(Configuration newConfig) {
         updateWidth();
+        if (mZenPanel != null) {
+            mZenPanel.updateLocale();
+        }
     }
 
     private void updateWidth() {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index ac7fc25..f829994 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -60,7 +60,7 @@
 
     private static final int[] MINUTE_BUCKETS = DEBUG
             ? new int[] { 0, 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 }
-            : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+            : ZenModeConfig.MINUTE_BUCKETS;
     private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
     private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
     private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
@@ -68,7 +68,6 @@
     private static final int TIME_CONDITION_INDEX = 1;
     private static final int FIRST_CONDITION_INDEX = 2;
     private static final float SILENT_HINT_PULSE_SCALE = 1.1f;
-    private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
 
     public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
 
@@ -121,10 +120,7 @@
         super.onFinishInflate();
 
         mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
-        mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
-        mZenButtons.addButton(R.string.interruption_level_priority,
-                Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-        mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
+        addZenButtons();
         mZenButtons.setCallback(mZenButtonsCallback);
 
         mZenSubhead = findViewById(R.id.zen_subhead);
@@ -174,6 +170,13 @@
         setExpanded(false);
     }
 
+    private void addZenButtons() {
+        mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
+        mZenButtons.addButton(R.string.interruption_level_priority,
+                Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
+    }
+
     public void setHidden(boolean hidden) {
         if (mHidden == hidden) return;
         mHidden = hidden;
@@ -213,7 +216,7 @@
                 mBucketIndex = -1;
             } else {
                 mBucketIndex = DEFAULT_BUCKET_INDEX;
-                mTimeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+                mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
             }
             if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
             mConditions = null; // reset conditions
@@ -234,6 +237,11 @@
         mController.addCallback(mZenCallback);
     }
 
+    public void updateLocale() {
+        mZenButtons.removeAllViews();
+        addZenButtons();
+    }
+
     private void setExitCondition(Condition exitCondition) {
         if (sameConditionId(mExitCondition, exitCondition)) return;
         mExitCondition = exitCondition;
@@ -254,7 +262,7 @@
     }
 
     private void refreshExitConditionText() {
-        final String forever = mContext.getString(R.string.zen_mode_forever);
+        final String forever = mContext.getString(com.android.internal.R.string.zen_mode_forever);
         if (mExitCondition == null) {
             mExitConditionText = forever;
         } else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
@@ -330,24 +338,7 @@
         if (time == 0) return null;
         final long span = time - System.currentTimeMillis();
         if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
-        return timeCondition(time, Math.round(span / (float)MINUTES_MS));
-    }
-
-    private Condition newTimeCondition(int minutesFromNow) {
-        final long now = System.currentTimeMillis();
-        final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
-        return timeCondition(now + millis, minutesFromNow);
-    }
-
-    private Condition timeCondition(long time, int minutes) {
-        final int num = minutes < 60 ? minutes : Math.round(minutes / 60f);
-        final int resId = minutes < 60
-                ? R.plurals.zen_mode_duration_minutes
-                : R.plurals.zen_mode_duration_hours;
-        final String caption = mContext.getResources().getQuantityString(resId, num, num);
-        final Uri id = ZenModeConfig.toCountdownConditionId(time);
-        return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
-                Condition.FLAG_RELEVANT_NOW);
+        return ZenModeConfig.toTimeCondition(time, Math.round(span / (float) MINUTES_MS));
     }
 
     private void handleUpdateConditions(Condition[] conditions) {
@@ -401,7 +392,7 @@
         if (favoriteIndex == -1) {
             getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
         } else {
-            mTimeCondition = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
+            mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
             mBucketIndex = favoriteIndex;
             bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
             getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
@@ -457,7 +448,7 @@
         });
         final TextView title = (TextView) row.findViewById(android.R.id.title);
         if (condition == null) {
-            title.setText(R.string.zen_mode_forever);
+            title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
         } else {
             title.setText(condition.summary);
         }
@@ -494,7 +485,7 @@
             } else {
                 final long span = time - System.currentTimeMillis();
                 button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
-                final Condition maxCondition = newTimeCondition(MAX_BUCKET_MINUTES);
+                final Condition maxCondition = ZenModeConfig.toTimeCondition(MAX_BUCKET_MINUTES);
                 button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
             }
 
@@ -520,18 +511,18 @@
                 final long bucketTime = now + bucketMinutes * MINUTES_MS;
                 if (up && bucketTime > time || !up && bucketTime < time) {
                     mBucketIndex = j;
-                    newCondition = timeCondition(bucketTime, bucketMinutes);
+                    newCondition = ZenModeConfig.toTimeCondition(bucketTime, bucketMinutes);
                     break;
                 }
             }
             if (newCondition == null) {
                 mBucketIndex = DEFAULT_BUCKET_INDEX;
-                newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+                newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
             }
         } else {
             // on a known index, simply increment or decrement
             mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
-            newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+            newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
         }
         mTimeCondition = newCondition;
         bind(mTimeCondition, row);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c8b5b3e..fefbe0a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -48,6 +49,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.service.trust.TrustAgentService;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -97,6 +99,7 @@
     private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
     /* package */ final TrustArchive mArchive = new TrustArchive();
     private final Context mContext;
+    private final LockPatternUtils mLockPatternUtils;
 
     private UserManager mUserManager;
 
@@ -104,6 +107,7 @@
         super(context);
         mContext = context;
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mLockPatternUtils = new LockPatternUtils(context);
     }
 
     @Override
@@ -116,6 +120,7 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
             mReceiver.register(mContext);
+            maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
             refreshAgentList(UserHandle.USER_ALL);
         }
     }
@@ -159,6 +164,11 @@
 
     void refreshAgentList(int userId) {
         if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+        if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) {
+            Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+                    + " must be USER_ALL or a specific user.", new Throwable("here"));
+            userId = UserHandle.USER_ALL;
+        }
         PackageManager pm = mContext.getPackageManager();
 
         List<UserInfo> userInfos;
@@ -168,12 +178,13 @@
             userInfos = new ArrayList<>();
             userInfos.add(mUserManager.getUserInfo(userId));
         }
-        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+        LockPatternUtils lockPatternUtils = mLockPatternUtils;
 
         ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
         obsoleteAgents.addAll(mActiveAgents);
 
         for (UserInfo userInfo : userInfos) {
+            if (!userInfo.supportsSwitchTo()) continue;
             if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
                     == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) continue;
             if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue;
@@ -186,22 +197,11 @@
             if (enabledAgents == null) {
                 continue;
             }
-            List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
-                    PackageManager.GET_META_DATA, userInfo.id);
+            List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userInfo.id);
             for (ResolveInfo resolveInfo : resolveInfos) {
-                if (resolveInfo.serviceInfo == null) continue;
-
-                String packageName = resolveInfo.serviceInfo.packageName;
-                if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    Log.w(TAG, "Skipping agent because package " + packageName
-                            + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
-                    continue;
-                }
-
                 ComponentName name = getComponentName(resolveInfo);
-                if (!enabledAgents.contains(name)) continue;
 
+                if (!enabledAgents.contains(name)) continue;
                 if (disableTrustAgents) {
                     List<String> features =
                             dpm.getTrustAgentFeaturesEnabled(null /* admin */, name);
@@ -228,11 +228,13 @@
         boolean trustMayHaveChanged = false;
         for (int i = 0; i < obsoleteAgents.size(); i++) {
             AgentInfo info = obsoleteAgents.valueAt(i);
-            if (info.agent.isManagingTrust()) {
-                trustMayHaveChanged = true;
+            if (userId == UserHandle.USER_ALL || userId == info.userId) {
+                if (info.agent.isManagingTrust()) {
+                    trustMayHaveChanged = true;
+                }
+                info.agent.unbind();
+                mActiveAgents.remove(info);
             }
-            info.agent.unbind();
-            mActiveAgents.remove(info);
         }
 
         if (trustMayHaveChanged) {
@@ -342,6 +344,54 @@
         return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
     }
 
+    private void maybeEnableFactoryTrustAgents(LockPatternUtils utils, int userId) {
+        if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
+            return;
+        }
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
+        ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            ComponentName componentName = getComponentName(resolveInfo);
+            int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
+            if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
+                        + "is not a system package.");
+                continue;
+            }
+            discoveredAgents.add(componentName);
+        }
+
+        List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
+        if (previouslyEnabledAgents != null) {
+            discoveredAgents.addAll(previouslyEnabledAgents);
+        }
+        utils.setEnabledTrustAgents(discoveredAgents, userId);
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
+    }
+
+    private List<ResolveInfo> resolveAllowedTrustAgents(PackageManager pm, int userId) {
+        List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
+                0 /* flags */, userId);
+        ArrayList<ResolveInfo> allowedAgents = new ArrayList<>(resolveInfos.size());
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            if (resolveInfo.serviceInfo == null) continue;
+            if (resolveInfo.serviceInfo.applicationInfo == null) continue;
+            String packageName = resolveInfo.serviceInfo.packageName;
+            if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
+                    != PackageManager.PERMISSION_GRANTED) {
+                ComponentName name = getComponentName(resolveInfo);
+                Log.w(TAG, "Skipping agent " + name + " because package does not have"
+                        + " permission " + PERMISSION_PROVIDE_AGENT + ".");
+                continue;
+            }
+            allowedAgents.add(resolveInfo);
+        }
+        return allowedAgents;
+    }
+
     // Agent dispatch and aggregation
 
     private boolean aggregateIsTrusted(int userId) {
@@ -414,6 +464,7 @@
             }
         }
         mTrustListeners.add(listener);
+        updateTrustAll();
     }
 
     private void removeListener(ITrustListener listener) {
@@ -616,12 +667,19 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
-                    intent.getAction())) {
+            String action = intent.getAction();
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
                 refreshAgentList(getSendingUserId());
                 updateDevicePolicyFeatures();
-            } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                 updateUserHasAuthenticated(getSendingUserId());
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -100);
+                if (userId > 0) {
+                    maybeEnableFactoryTrustAgents(mLockPatternUtils, userId);
+                } else {
+                    Log.wtf(TAG, "EXTRA_USER_HANDLE missing or invalid, value=" + userId);
+                }
             }
         }
 
@@ -629,6 +687,7 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
             filter.addAction(Intent.ACTION_USER_PRESENT);
+            filter.addAction(Intent.ACTION_USER_ADDED);
             context.registerReceiverAsUser(this,
                     UserHandle.ALL,
                     filter,