Merge "Updated haptic effect for success" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 35a2689..1789d1d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -805,6 +805,7 @@
 Landroid/content/pm/PackageParser$Package;->mPreferredOrder:I
 Landroid/content/pm/PackageParser$Package;->mSharedUserId:Ljava/lang/String;
 Landroid/content/pm/PackageParser$Package;->mSharedUserLabel:I
+Landroid/content/pm/PackageParser$Package;->mSigningDetails:Landroid/content/pm/PackageParser$SigningDetails;
 Landroid/content/pm/PackageParser$Package;->mVersionCode:I
 Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String;
 Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
@@ -821,6 +822,7 @@
 Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
 Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo;
 Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
+Landroid/content/pm/PackageParser$SigningDetails;->signatures:[Landroid/content/pm/Signature;
 Landroid/content/pm/PackageParser;-><init>()V
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
@@ -884,6 +886,7 @@
 Landroid/content/res/DrawableCache;-><init>()V
 Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
 Landroid/content/res/ObbInfo;->salt:[B
+Landroid/content/res/Resources$Theme;->mThemeImpl:Landroid/content/res/ResourcesImpl$ThemeImpl;
 Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
 Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
 Landroid/content/res/Resources;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
@@ -1465,6 +1468,7 @@
 Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
 Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getCaptureSession()Ljava/lang/Integer;
 Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getData()[B
+Landroid/media/soundtrigger/SoundTriggerManager;->isRecognitionActive(Ljava/util/UUID;)Z
 Landroid/media/soundtrigger/SoundTriggerManager;->loadSoundModel(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/app/PendingIntent;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/os/Bundle;Landroid/content/ComponentName;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
@@ -2282,6 +2286,7 @@
 Landroid/renderscript/RenderScriptCacheDir;->mCacheDir:Ljava/io/File;
 Landroid/renderscript/RenderScriptCacheDir;->setupDiskCache(Ljava/io/File;)V
 Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J
+Landroid/security/keystore/recovery/RecoveryController;->getRecoveryStatus(Ljava/lang/String;Ljava/lang/String;)I
 Landroid/security/keystore/recovery/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V
 Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
 Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 97c9fa5..7338bfe 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -236,6 +236,17 @@
             int userId, Intent[] intents, Bundle bOptions);
 
     /**
+     * Start activity {@code intent} without calling user-id check.
+     *
+     * - DO NOT call it with the calling UID cleared.
+     * - The caller must do the calling user ID check.
+     *
+     * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
+     */
+    public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage,
+            Intent intent, @Nullable Bundle options, int userId);
+
+    /**
      * Get the procstate for the UID.  The return value will be between
      * {@link ActivityManager#MIN_PROCESS_STATE} and {@link ActivityManager#MAX_PROCESS_STATE}.
      * Note if the UID doesn't exist, it'll return {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 725f240..327d4fe 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2722,7 +2722,40 @@
      * @hide
      */
     public static boolean areRemoteViewsChanged(Builder first, Builder second) {
-        return !first.usesStandardHeader() || !second.usesStandardHeader();
+        if (!Objects.equals(first.usesStandardHeader(), second.usesStandardHeader())) {
+            return true;
+        }
+
+        if (areRemoteViewsChanged(first.mN.contentView, second.mN.contentView)) {
+            return true;
+        }
+        if (areRemoteViewsChanged(first.mN.bigContentView, second.mN.bigContentView)) {
+            return true;
+        }
+        if (areRemoteViewsChanged(first.mN.headsUpContentView, second.mN.headsUpContentView)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean areRemoteViewsChanged(RemoteViews first, RemoteViews second) {
+        if (first == null && second == null) {
+            return false;
+        }
+        if (first == null && second != null || first != null && second == null) {
+            return true;
+        }
+
+        if (!Objects.equals(first.getLayoutId(), second.getLayoutId())) {
+            return true;
+        }
+
+        if (!Objects.equals(first.getSequenceNumber(), second.getSequenceNumber())) {
+            return true;
+        }
+
+        return false;
     }
 
     /**
diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java
index 20c1390..746beaf 100644
--- a/core/java/android/app/slice/SliceMetrics.java
+++ b/core/java/android/app/slice/SliceMetrics.java
@@ -18,9 +18,11 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.metrics.LogMaker;
 import android.net.Uri;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 /**
  * Metrics interface for slices.
@@ -34,24 +36,38 @@
 
     private static final String TAG = "SliceMetrics";
     private MetricsLogger mMetricsLogger;
+    private LogMaker mLogMaker;
 
     /**
      * An object to be used throughout the life of a slice to register events.
      */
     public SliceMetrics(@NonNull Context context, @NonNull Uri uri) {
         mMetricsLogger = new MetricsLogger();
+        mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
+        mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_AUTHORITY, uri.getAuthority());
+        mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_PATH, uri.getPath());
     }
 
     /**
      * To be called whenever the slice becomes visible to the user.
      */
     public void logVisible() {
+        synchronized (mLogMaker)  {
+            mLogMaker.setCategory(MetricsEvent.SLICE)
+                    .setType(MetricsEvent.TYPE_OPEN);
+            mMetricsLogger.write(mLogMaker);
+        }
     }
 
     /**
      * To be called whenever the slice becomes invisible to the user.
      */
     public void logHidden() {
+        synchronized (mLogMaker)  {
+            mLogMaker.setCategory(MetricsEvent.SLICE)
+                    .setType(MetricsEvent.TYPE_CLOSE);
+            mMetricsLogger.write(mLogMaker);
+        }
     }
 
     /**
@@ -68,5 +84,12 @@
      * @param subSlice The URI of the sub-slice that is the subject of the interaction.
      */
     public void logTouch(int actionType, @NonNull Uri subSlice) {
+        synchronized (mLogMaker)  {
+            mLogMaker.setCategory(MetricsEvent.SLICE)
+                    .setType(MetricsEvent.TYPE_ACTION)
+                    .addTaggedData(MetricsEvent.FIELD_SUBSLICE_AUTHORITY, subSlice.getAuthority())
+                    .addTaggedData(MetricsEvent.FIELD_SUBSLICE_PATH, subSlice.getPath());
+            mMetricsLogger.write(mLogMaker);
+        }
     }
 }
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index ae1c207..ba7710b 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -42,10 +43,10 @@
             String callingPackage, String packageName, in UserHandle user);
     ActivityInfo resolveActivity(
             String callingPackage, in ComponentName component, in UserHandle user);
-    void startActivityAsUser(String callingPackage,
+    void startActivityAsUser(in IApplicationThread caller, String callingPackage,
             in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
-    void showAppDetailsAsUser(
+    void showAppDetailsAsUser(in IApplicationThread caller,
             String callingPackage, in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
     boolean isPackageEnabled(String callingPackage, String packageName, in UserHandle user);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8717601..fa423e2 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -548,7 +548,8 @@
             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
         }
         try {
-            mService.startActivityAsUser(mContext.getPackageName(),
+            mService.startActivityAsUser(mContext.getIApplicationThread(),
+                    mContext.getPackageName(),
                     component, sourceBounds, opts, user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -568,7 +569,8 @@
             Rect sourceBounds, Bundle opts) {
         logErrorForInvalidProfileAccess(user);
         try {
-            mService.showAppDetailsAsUser(mContext.getPackageName(),
+            mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
+                    mContext.getPackageName(),
                     component, sourceBounds, opts, user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fdae191..9e56d14 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1785,6 +1785,12 @@
     public static final int USER_SETUP_PERSONALIZATION_STARTED = 1;
 
     /**
+     * User has snoozed personalization and will complete it later.
+     * @hide
+     */
+    public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2;
+
+    /**
      * User has completed setup personalization.
      * @hide
      */
@@ -1795,6 +1801,7 @@
     @IntDef({
             USER_SETUP_PERSONALIZATION_NOT_STARTED,
             USER_SETUP_PERSONALIZATION_STARTED,
+            USER_SETUP_PERSONALIZATION_PAUSED,
             USER_SETUP_PERSONALIZATION_COMPLETE
     })
     public @interface UserSetupPersonalization {}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 309fa4a..510626b 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,10 @@
 
 package android.service.notification;
 
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.NotificationManager;
@@ -68,6 +72,7 @@
     public static final int SOURCE_STAR = 2;
     public static final int MAX_SOURCE = SOURCE_STAR;
     private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
+    private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR;
 
     public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
     public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
@@ -93,13 +98,10 @@
     private static final boolean DEFAULT_ALLOW_REMINDERS = false;
     private static final boolean DEFAULT_ALLOW_EVENTS = false;
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
-    private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
-    private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
     private static final boolean DEFAULT_CHANNELS_BYPASSING_DND = false;
-    private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
-            Policy.getAllSuppressedVisualEffects();
+    private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS = 0;
 
-    public static final int XML_VERSION = 7;
+    public static final int XML_VERSION = 8;
     public static final String ZEN_TAG = "zen";
     private static final String ZEN_ATT_VERSION = "version";
     private static final String ZEN_ATT_USER = "user";
@@ -151,12 +153,10 @@
     public boolean allowMessages = DEFAULT_ALLOW_MESSAGES;
     public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
     public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
-    public int allowCallsFrom = DEFAULT_SOURCE;
+    public int allowCallsFrom = DEFAULT_CALLS_SOURCE;
     public int allowMessagesFrom = DEFAULT_SOURCE;
     public int user = UserHandle.USER_SYSTEM;
     public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
-    public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
-    public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
     public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND;
     public int version;
 
@@ -185,8 +185,6 @@
                 automaticRules.put(ids[i], rules[i]);
             }
         }
-        allowWhenScreenOff = source.readInt() == 1;
-        allowWhenScreenOn = source.readInt() == 1;
         allowAlarms = source.readInt() == 1;
         allowMedia = source.readInt() == 1;
         allowSystem = source.readInt() == 1;
@@ -219,8 +217,6 @@
         } else {
             dest.writeInt(0);
         }
-        dest.writeInt(allowWhenScreenOff ? 1 : 0);
-        dest.writeInt(allowWhenScreenOn ? 1 : 0);
         dest.writeInt(allowAlarms ? 1 : 0);
         dest.writeInt(allowMedia ? 1 : 0);
         dest.writeInt(allowSystem ? 1 : 0);
@@ -242,8 +238,6 @@
                 .append(",allowMessages=").append(allowMessages)
                 .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
                 .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
-                .append(",allowWhenScreenOff=").append(allowWhenScreenOff)
-                .append(",allowWhenScreenOn=").append(allowWhenScreenOn)
                 .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
                 .append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
                 .append(",automaticRules=").append(automaticRules)
@@ -289,12 +283,6 @@
         if (allowMessagesFrom != to.allowMessagesFrom) {
             d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom);
         }
-        if (allowWhenScreenOff != to.allowWhenScreenOff) {
-            d.addLine("allowWhenScreenOff", allowWhenScreenOff, to.allowWhenScreenOff);
-        }
-        if (allowWhenScreenOn != to.allowWhenScreenOn) {
-            d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
-        }
         if (suppressedVisualEffects != to.suppressedVisualEffects) {
             d.addLine("suppressedVisualEffects", suppressedVisualEffects,
                     to.suppressedVisualEffects);
@@ -404,8 +392,6 @@
                 && other.allowMessagesFrom == allowMessagesFrom
                 && other.allowReminders == allowReminders
                 && other.allowEvents == allowEvents
-                && other.allowWhenScreenOff == allowWhenScreenOff
-                && other.allowWhenScreenOn == allowWhenScreenOn
                 && other.user == user
                 && Objects.equals(other.automaticRules, automaticRules)
                 && Objects.equals(other.manualRule, manualRule)
@@ -418,7 +404,7 @@
         return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
                 allowRepeatCallers, allowMessages,
                 allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
-                allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+                user, automaticRules, manualRule,
                 suppressedVisualEffects, areChannelsBypassingDnd);
     }
 
@@ -472,6 +458,7 @@
         final ZenModeConfig rt = new ZenModeConfig();
         rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
         rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
+        boolean readSuppressedEffects = false;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
             tag = parser.getName();
             if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
@@ -502,17 +489,33 @@
                         rt.allowCallsFrom = DEFAULT_SOURCE;
                         rt.allowMessagesFrom = DEFAULT_SOURCE;
                     }
-                    // continue to read even though we now have suppressedVisualEffects, in case
-                    // we need to revert to users' previous settings
-                    rt.allowWhenScreenOff =
-                            safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
-                    rt.allowWhenScreenOn =
-                            safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
                     rt.allowAlarms = safeBoolean(parser, ALLOW_ATT_ALARMS, DEFAULT_ALLOW_ALARMS);
                     rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
                             DEFAULT_ALLOW_MEDIA);
                     rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
-                } else if (DISALLOW_TAG.equals(tag)) {
+
+                    // migrate old suppressed visual effects fields, if they still exist in the xml
+                    Boolean allowWhenScreenOff = unsafeBoolean(parser, ALLOW_ATT_SCREEN_OFF);
+                    if (allowWhenScreenOff != null) {
+                        readSuppressedEffects = true;
+                        if (allowWhenScreenOff) {
+                            rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS
+                                    | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+                        }
+                    }
+                    Boolean allowWhenScreenOn = unsafeBoolean(parser, ALLOW_ATT_SCREEN_ON);
+                    if (allowWhenScreenOn != null) {
+                        readSuppressedEffects = true;
+                        if (allowWhenScreenOn) {
+                            rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+                        }
+                    }
+                    if (readSuppressedEffects) {
+                        Slog.d(TAG, "Migrated visual effects to " + rt.suppressedVisualEffects);
+                    }
+                } else if (DISALLOW_TAG.equals(tag) && !readSuppressedEffects) {
+                    // only read from suppressed visual effects field if we haven't just migrated
+                    // the values from allowOn/allowOff, lest we wipe out those settings
                     rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
                             DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
                 } else if (MANUAL_TAG.equals(tag)) {
@@ -552,8 +555,6 @@
         out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
         out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
         out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
-        out.attribute(null, ALLOW_ATT_SCREEN_OFF, Boolean.toString(allowWhenScreenOff));
-        out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowWhenScreenOn));
         out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
         out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia));
         out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
@@ -673,6 +674,12 @@
         return source >= SOURCE_ANYONE && source <= MAX_SOURCE;
     }
 
+    private static Boolean unsafeBoolean(XmlPullParser parser, String att) {
+        final String val = parser.getAttributeValue(null, att);
+        if (TextUtils.isEmpty(val)) return null;
+        return Boolean.parseBoolean(val);
+    }
+
     private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
         final String val = parser.getAttributeValue(null, att);
         return safeBoolean(val, defValue);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1c2e43e..6bacdfe 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -901,7 +901,7 @@
      * Refreshes this info with the latest state of the view it represents, and request new
      * data be added by the View.
      *
-     * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
+     * @param extraDataKey The extra data requested. Data that must be requested
      *                     with this mechanism is generally expensive to retrieve, so should only be
      *                     requested when needed. See
      *                     {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ced66cd..e7c3a47 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1373,7 +1373,7 @@
      * indicator. To animate the visual position to the target value, use
      * {@link #setProgress(int, boolean)}}.
      *
-     * @param progress the new progress, between 0 and {@link #getMax()}
+     * @param progress the new progress, between {@link #getMin()} and {@link #getMax()}
      *
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1392,7 +1392,7 @@
      * Animation does not affect the result of {@link #getProgress()}, which
      * will return the target value immediately after this method is called.
      *
-     * @param progress the new progress value, between 0 and {@link #getMax()}
+     * @param progress the new progress value, between {@link #getMin()} and {@link #getMax()}
      * @param animate {@code true} to animate between the current and target
      *                values or {@code false} to not animate
      */
@@ -1425,7 +1425,8 @@
      * anything if the progress bar is in indeterminate mode.
      * </p>
      *
-     * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
+     * @param secondaryProgress the new secondary progress, between {@link #getMin()} and
+     * {@link #getMax()}
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
      * @see #getSecondaryProgress()
@@ -1455,7 +1456,7 @@
      * <p>Get the progress bar's current level of progress. Return 0 when the
      * progress bar is in indeterminate mode.</p>
      *
-     * @return the current progress, between 0 and {@link #getMax()}
+     * @return the current progress, between {@link #getMin()} and {@link #getMax()}
      *
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1472,7 +1473,7 @@
      * <p>Get the progress bar's current level of secondary progress. Return 0 when the
      * progress bar is in indeterminate mode.</p>
      *
-     * @return the current secondary progress, between 0 and {@link #getMax()}
+     * @return the current secondary progress, between {@link #getMin()} and {@link #getMax()}
      *
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1990,7 +1991,8 @@
 
         if (!isIndeterminate()) {
             AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(
-                    AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, 0, getMax(), getProgress());
+                    AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
+                    getProgress());
             info.setRangeInfo(rangeInfo);
         }
     }
diff --git a/core/res/res/drawable/ic_dnd_block_notifications.xml b/core/res/res/drawable/ic_dnd_block_notifications.xml
new file mode 100644
index 0000000..4983614
--- /dev/null
+++ b/core/res/res/drawable/ic_dnd_block_notifications.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="40dp"
+        android:height="40dp"
+        android:viewportWidth="40.0"
+        android:viewportHeight="40.0">
+    <path
+        android:pathData="M34,20H2c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h32c1.1,0 2,0.9 2,2v12C36,19.1 35.1,20 34,20z"
+        android:fillColor="#FBBC04"/>
+    <path
+        android:pathData="M4.63,10L4.63,10c-0.83,0 -1.5,-0.67 -1.5,-1.5v0C3.12,7.67 3.8,7 4.62,7h0c0.82,0 1.5,0.67 1.5,1.5v0C6.12,9.33 5.45,10 4.63,10z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M8.62,7.5h9.5v2h-9.5z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M3.12,15h24v2h-24z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M3.12,12h17.5v2h-17.5z"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M33.59,6.41m-5.78,0a5.78,5.78 0,1 1,11.56 0a5.78,5.78 0,1 1,-11.56 0"
+        android:fillColor="#FFFFFF"/>
+    <path
+        android:pathData="M33.5,0C29.91,0 27,2.91 27,6.5s2.91,6.5 6.5,6.5S40,10.09 40,6.5S37.09,0 33.5,0zM33.5,11.7c-2.87,0 -5.2,-2.33 -5.2,-5.2s2.33,-5.2 5.2,-5.2s5.2,2.33 5.2,5.2S36.37,11.7 33.5,11.7z"
+        android:fillColor="#4285F4"/>
+    <path
+        android:pathData="M30.25,5.85h6.5v1.3h-6.5z"
+        android:fillColor="#4285F4"/>
+</vector>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5298e5b..c3ab1a6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2555,6 +2555,7 @@
   <java-symbol type="drawable" name="ic_storage_48dp" />
   <java-symbol type="drawable" name="ic_usb_48dp" />
   <java-symbol type="drawable" name="ic_zen_24dp" />
+  <java-symbol type="drawable" name="ic_dnd_block_notifications" />
 
   <!-- Floating toolbar -->
   <java-symbol type="id" name="floating_toolbar_menu_item_image" />
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 3a71851..ba8173e 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -19,7 +19,7 @@
 
 <!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
 <zen version="7">
-    <allow alarms="true" media="true" system="false" calls="false" messages="false"
+    <allow alarms="true" media="true" system="false" calls="false" callsFrom="2" messages="false"
            reminders="false" events="false" />
 
     <!-- all visual effects that exist as of P -->
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index be7d663..569de76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -40,7 +40,6 @@
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
-    SkSafeUnref(mColorFilter);
     setTransform(nullptr);
     mRenderState.unregisterDeferredLayerUpdater(this);
     destroyLayer();
@@ -67,8 +66,11 @@
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
     mAlpha = PaintUtils::getAlphaDirect(paint);
     mMode = PaintUtils::getBlendModeDirect(paint);
-    SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
-    SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+    if (paint) {
+        mColorFilter = paint->refColorFilter();
+    } else {
+        mColorFilter.reset();
+    }
 }
 
 void DeferredLayerUpdater::apply() {
@@ -143,7 +145,7 @@
 #endif
         mSurfaceTexture->getTransformMatrix(transform);
 
-        updateLayer(forceFilter, transform);
+        updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
     }
 }
 
@@ -153,17 +155,19 @@
                         Layer::Api::OpenGL, Layer::Api::Vulkan);
 
     static const mat4 identityMatrix;
-    updateLayer(false, identityMatrix.data);
+    updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
 
     VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
     vkLayer->updateTexture();
 }
 
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
+                                       android_dataspace dataspace) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
     mLayer->getTexTransform().load(textureTransform);
+    mLayer->setDataSpace(dataspace);
 }
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9dc029f..fe3ee7a 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -20,6 +20,7 @@
 #include <SkMatrix.h>
 #include <cutils/compiler.h>
 #include <gui/GLConsumer.h>
+#include <system/graphics.h>
 #include <utils/StrongPointer.h>
 
 #include <GLES2/gl2.h>
@@ -41,7 +42,7 @@
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
     typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
-                                 uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+                                 uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
                                  SkBlendMode mode, bool blend)>
             CreateLayerFn;
     ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
@@ -96,7 +97,7 @@
 
     void detachSurfaceTexture();
 
-    void updateLayer(bool forceFilter, const float* textureTransform);
+    void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
 
     void destroyLayer();
 
@@ -109,7 +110,7 @@
     int mWidth = 0;
     int mHeight = 0;
     bool mBlend = false;
-    SkColorFilter* mColorFilter = nullptr;
+    sk_sp<SkColorFilter> mColorFilter;
     int mAlpha = 255;
     SkBlendMode mMode = SkBlendMode::kSrcOver;
     sp<GLConsumer> mSurfaceTexture;
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 32a3014..42ae29d 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,7 +32,7 @@
 namespace uirenderer {
 
 GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                 SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+                 sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
         : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
         , caches(Caches::getInstance())
         , texture(caches) {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 1b09191..28749a0 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -32,7 +32,7 @@
 class GlLayer : public Layer {
 public:
     GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
+            sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
     virtual ~GlLayer();
 
     uint32_t getWidth() const override { return texture.mWidth; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 86950d5..fb8f033 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,34 +18,58 @@
 
 #include "renderstate/RenderState.h"
 
-#include <SkColorFilter.h>
+#include <SkToSRGBColorFilter.h>
 
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
              SkBlendMode mode)
         : GpuMemoryTracker(GpuObjectType::Layer)
         , mRenderState(renderState)
         , mApi(api)
-        , colorFilter(nullptr)
+        , mColorFilter(colorFilter)
         , alpha(alpha)
         , mode(mode) {
     // TODO: This is a violation of Android's typical ref counting, but it
     // preserves the old inc/dec ref locations. This should be changed...
     incStrong(nullptr);
-
+    buildColorSpaceWithFilter();
     renderState.registerLayer(this);
 }
 
 Layer::~Layer() {
-    SkSafeUnref(colorFilter);
-
     mRenderState.unregisterLayer(this);
 }
 
-void Layer::setColorFilter(SkColorFilter* filter) {
-    SkRefCnt_SafeAssign(colorFilter, filter);
+void Layer::setColorFilter(sk_sp<SkColorFilter> filter) {
+    if (filter != mColorFilter) {
+        mColorFilter = filter;
+        buildColorSpaceWithFilter();
+    }
+}
+
+void Layer::setDataSpace(android_dataspace dataspace) {
+    if (dataspace != mCurrentDataspace) {
+        mCurrentDataspace = dataspace;
+        buildColorSpaceWithFilter();
+    }
+}
+
+void Layer::buildColorSpaceWithFilter() {
+    sk_sp<SkColorFilter> colorSpaceFilter;
+    sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace);
+    if (colorSpace && !colorSpace->isSRGB()) {
+        colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+    }
+
+    if (mColorFilter && colorSpaceFilter) {
+        mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter);
+    } else if (colorSpaceFilter) {
+        mColorSpaceWithFilter = colorSpaceFilter;
+    } else {
+        mColorSpaceWithFilter = mColorFilter;
+    }
 }
 
 void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6921381..89bcddc 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,8 @@
 #include <GpuMemoryTracker.h>
 #include <utils/RefBase.h>
 
+#include <SkColorFilter.h>
+#include <SkColorSpace.h>
 #include <SkBlendMode.h>
 #include <SkPaint.h>
 
@@ -72,9 +74,15 @@
 
     inline SkBlendMode getMode() const { return mode; }
 
-    inline SkColorFilter* getColorFilter() const { return colorFilter; }
+    inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
 
-    void setColorFilter(SkColorFilter* filter);
+    void setColorFilter(sk_sp<SkColorFilter> filter);
+
+    void setDataSpace(android_dataspace dataspace);
+
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+    inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
 
     inline mat4& getTexTransform() { return texTransform; }
 
@@ -87,18 +95,30 @@
     void postDecStrong();
 
 protected:
-    Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+    Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha,
           SkBlendMode mode);
 
     RenderState& mRenderState;
 
 private:
+    void buildColorSpaceWithFilter();
+
     Api mApi;
 
     /**
      * Color filter used to draw this layer. Optional.
      */
-    SkColorFilter* colorFilter;
+    sk_sp<SkColorFilter> mColorFilter;
+
+    /**
+     * Colorspace of the contents of the layer. Optional.
+     */
+    android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN;
+
+    /**
+     * A color filter that is the combination of the mColorFilter and mColorSpace. Optional.
+     */
+    sk_sp<SkColorFilter> mColorSpaceWithFilter;
 
     /**
      * Indicates raster data backing the layer is scaled, requiring filtration.
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index f23f472..e9664d0 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -28,7 +28,7 @@
 class VkLayer : public Layer {
 public:
     VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+            sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
             : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
             , mWidth(layerWidth)
             , mHeight(layerHeight)
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 293e45f..4f16ddb 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -51,8 +51,13 @@
         GrGLTextureInfo externalTexture;
         externalTexture.fTarget = glLayer->getRenderTarget();
         externalTexture.fID = glLayer->getTextureId();
-        GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
-                                        externalTexture);
+        // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
+        // expose that info we use it as our default.  Further, given that we only use this texture
+        // as a source this will not impact how Skia uses the texture.  The only potential affect
+        // this is anticipated to have is that for some format types if we are not bound as an OES
+        // texture we may get invalid results for SKP capture if we read back the texture.
+        externalTexture.fFormat = GL_RGBA8;
+        GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
         layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
                                               kPremul_SkAlphaType, nullptr);
     } else {
@@ -82,7 +87,7 @@
         SkPaint paint;
         paint.setAlpha(layer->getAlpha());
         paint.setBlendMode(layer->getMode());
-        paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
+        paint.setColorFilter(layer->getColorSpaceWithFilter());
 
         const bool nonIdentityMatrix = !matrix.isIdentity();
         if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 74cfb28..d732a46 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -152,7 +152,7 @@
 }
 
 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                          SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+                          sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) {
     GlLayer* layer =
             new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
     layer->generateTexture();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9e73046..d66cba1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -147,6 +147,7 @@
             GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
             if (cachedContext.get() != currentContext) {
                 if (cachedContext.get()) {
+                    ATRACE_NAME("flush layers (context changed)");
                     cachedContext->flush();
                 }
                 cachedContext.reset(SkSafeRef(currentContext));
@@ -155,6 +156,7 @@
     }
 
     if (cachedContext.get()) {
+        ATRACE_NAME("flush layers");
         cachedContext->flush();
     }
 }
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 6530074..5825060 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,8 @@
 }
 
 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                          SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+                          sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+                          bool blend) {
     return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
 }
 
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 876af47..f96001e 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -123,7 +123,8 @@
 }
 
 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                          SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+                          sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+                          bool blend) {
     GlLayer* layer =
             new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
     Caches::getInstance().textureState().activateTexture(0);
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index b99854e..02ac97e 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -75,7 +75,7 @@
     layerUpdater->setTransform(&transform);
 
     // updateLayer so it's ready to draw
-    layerUpdater->updateLayer(true, Matrix4::identity().data);
+    layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         static_cast<GlLayer*>(layerUpdater->backingLayer())
                 ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index b8b5050..f29830f 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,7 @@
     // push the deferred updates to the layer
     Matrix4 scaledMatrix;
     scaledMatrix.loadScale(0.5, 0.5, 0.0);
-    layerUpdater->updateLayer(true, scaledMatrix.data);
+    layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
         glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index c2af867..75740e8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,6 +16,8 @@
 
 #include "Color.h"
 
+
+#include <utils/Log.h>
 #include <cmath>
 
 namespace android {
@@ -53,5 +55,57 @@
     return false;
 }
 
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+
+    SkColorSpace::Gamut gamut;
+    switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            gamut = SkColorSpace::kSRGB_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_BT2020:
+            gamut = SkColorSpace::kRec2020_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            gamut = SkColorSpace::kDCIP3_D65_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            gamut = SkColorSpace::kAdobeRGB_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+            return nullptr;
+        case HAL_DATASPACE_STANDARD_BT601_625:
+        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT601_525:
+        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+        case HAL_DATASPACE_STANDARD_BT470M:
+        case HAL_DATASPACE_STANDARD_FILM:
+        default:
+            ALOGW("Unsupported Gamut: %d", dataspace);
+            return nullptr;
+    }
+
+    switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+        case HAL_DATASPACE_TRANSFER_LINEAR:
+            return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+        case HAL_DATASPACE_TRANSFER_SRGB:
+            return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+            return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+            return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+            return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+            return nullptr;
+        case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+        case HAL_DATASPACE_TRANSFER_ST2084:
+        case HAL_DATASPACE_TRANSFER_HLG:
+        default:
+            ALOGW("Unsupported Gamma: %d", dataspace);
+            return nullptr;
+    }
+}
+
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 7ac0d96..2bec1f5 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
 #define COLOR_H
 
 #include <math.h>
+#include <system/graphics.h>
 
 #include <SkColor.h>
 #include <SkColorSpace.h>
@@ -111,6 +112,8 @@
 // approximated with the native sRGB transfer function. This method
 // returns true for sRGB, gamma 2.2 and Display P3 for instance
 bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1d3e521..32aafea 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 164;
+            private static final int SETTINGS_VERSION = 165;
 
             private final int mUserId;
 
@@ -3710,17 +3710,7 @@
                 }
 
                 if (currentVersion == 162) {
-                    // Version 162: Add a gesture for silencing phones
-                    final SettingsState settings = getGlobalSettingsLocked();
-                    final Setting currentSetting = settings.getSettingLocked(
-                            Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
-                    if (!currentSetting.isNull()
-                            && TextUtils.equals("0", currentSetting.getValue())) {
-                        settings.insertSettingLocked(
-                                Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
-                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
-                    }
-
+                    // Version 162: REMOVED: Add a gesture for silencing phones
                     currentVersion = 163;
                 }
 
@@ -3742,6 +3732,21 @@
                     currentVersion = 164;
                 }
 
+                if (currentVersion == 164) {
+                    // Version 164: Add a gesture for silencing phones
+                    final SettingsState settings = getGlobalSettingsLocked();
+                    final Setting currentSetting = settings.getSettingLocked(
+                            Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
+                    if (!currentSetting.isNull()
+                            && TextUtils.equals("0", currentSetting.getValue())) {
+                        settings.insertSettingLocked(
+                                Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 165;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index c464ba6..93adaa0 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -21,9 +21,9 @@
     <item>
         <inset
             android:insetLeft="0dp"
-            android:insetTop="7dp"
+            android:insetTop="8dp"
             android:insetRight="0dp"
-            android:insetBottom="5dp">
+            android:insetBottom="8dp">
             <shape android:shape="rectangle">
                 <corners android:radius="8dp" />
                 <stroke android:width="1dp" android:color="@color/smart_reply_button_stroke" />
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index 98e6e82..a490c4b 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -26,7 +26,7 @@
         android:paddingVertical="@dimen/smart_reply_button_padding_vertical"
         android:background="@drawable/smart_reply_button_background"
         android:gravity="center"
-        android:fontFamily="sans-serif-medium"
+        android:fontFamily="roboto-medium"
         android:textSize="@dimen/smart_reply_button_font_size"
         android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
         android:textColor="@color/smart_reply_button_text"
diff --git a/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
new file mode 100644
index 0000000..eff9b36
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
@@ -0,0 +1,34 @@
+<!--
+    Copyright 2018, The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<!-- Extends Framelayout -->
+<com.android.systemui.statusbar.DndSuppressingNotificationsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/hidden_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:visibility="gone">
+    <TextView
+        android:id="@+id/hidden_notifications"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="64dp"
+        android:paddingTop="28dp"
+        android:gravity="top|center_horizontal"
+        android:textColor="?attr/wallpaperTextColor"
+        android:textSize="16sp"
+        android:text="@string/dnd_suppressing_shade_text"/>
+</com.android.systemui.statusbar.DndSuppressingNotificationsView>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 438d2f5..eb71911 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -930,12 +930,13 @@
     <!-- Home button padding for sizing -->
     <dimen name="home_padding">16dp</dimen>
 
-    <!-- Smart reply button -->
+    <!-- Smart reply button. Total height 48dp, visible height 32dp. -->
     <dimen name="smart_reply_button_spacing">8dp</dimen>
-    <dimen name="smart_reply_button_padding_vertical">10dp</dimen>
-    <dimen name="smart_reply_button_padding_horizontal_single_line">16dp</dimen>
-    <dimen name="smart_reply_button_padding_horizontal_double_line">16dp</dimen>
-    <dimen name="smart_reply_button_min_height">32dp</dimen>
+    <dimen name="smart_reply_button_padding_vertical">14dp</dimen>
+    <!-- Note: The following two paddings need to be different until b/78876518 is fixed. -->
+    <dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
+    <dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
+    <dimen name="smart_reply_button_min_height">48dp</dimen>
     <dimen name="smart_reply_button_font_size">14sp</dimen>
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 697ab06..50e7b5c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
     <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
     <!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
+    <!-- Content description of the Trusted Face icon for accessibility. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_scanning_face">Scanning face</string>
     <!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
     <string name="accessibility_send_smart_reply">Send</string>
     <!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
@@ -1062,7 +1064,7 @@
     <string name="manage_notifications_text">Manage notifications</string>
 
     <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
-    <string name="dnd_suppressing_shade_text">Do Not Disturb is hiding notifications</string>
+    <string name="dnd_suppressing_shade_text">Notifications hidden by Do Not Disturb</string>
 
     <!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
     <string name="media_projection_action_text">Start now</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
new file mode 100644
index 0000000..db3a02d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.IntegerRes;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
+
+public class DndSuppressingNotificationsView extends StackScrollerDecorView {
+
+    private TextView mText;
+    private @StringRes int mTextId = R.string.dnd_suppressing_shade_text;
+
+    public DndSuppressingNotificationsView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mText.setText(mTextId);
+    }
+
+    @Override
+    protected View findContentView() {
+        return findViewById(R.id.hidden_container);
+    }
+
+    @Override
+    protected View findSecondaryView() {
+        return null;
+    }
+
+    public void setColor(@ColorInt int color) {
+        mText.setTextColor(color);
+    }
+
+    public void setOnContentClickListener(OnClickListener listener) {
+        mText.setOnClickListener(listener);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mText = findViewById(R.id.hidden_notifications);
+    }
+
+    @Override
+    public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+        return new DndSuppressingViewState();
+    }
+
+    public class DndSuppressingViewState extends ExpandableViewState {
+        @Override
+        public void applyToView(View view) {
+            super.applyToView(view);
+            if (view instanceof DndSuppressingNotificationsView) {
+                DndSuppressingNotificationsView dndView = (DndSuppressingNotificationsView) view;
+                boolean visible = this.clipTopAmount <= mText.getPaddingTop() * 0.6f;
+                dndView.performVisibilityAnimation(visible && !dndView.willBeGone());
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 42c774e..3efeb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -76,6 +76,7 @@
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.NotificationCounters;
 import com.android.systemui.statusbar.notification.NotificationInflater;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
@@ -1252,6 +1253,8 @@
                 Dependency.get(NotificationBlockingHelperManager.class);
         boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
 
+        Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+
         // Continue with dismiss since we don't want the blocking helper to be directly associated
         // with a certain notification.
         performDismiss(fromAccessibility);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index bc572a2..0cc6137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -30,6 +30,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -270,7 +271,8 @@
 
 
     /** Animates out the guts view via either a fade or a circular reveal. */
-    private void animateClose(int x, int y, boolean shouldDoCircularReveal) {
+    @VisibleForTesting
+    void animateClose(int x, int y, boolean shouldDoCircularReveal) {
         if (shouldDoCircularReveal) {
             // Circular reveal originating at (x, y)
             if (x == -1 || y == -1) {
@@ -340,7 +342,8 @@
         }
     }
 
-    private void setExposed(boolean exposed, boolean needsFalsingProtection) {
+    @VisibleForTesting
+    void setExposed(boolean exposed, boolean needsFalsingProtection) {
         final boolean wasExposed = mExposed;
         mExposed = exposed;
         mNeedsFalsingProtection = needsFalsingProtection;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 6a1740c..ec49f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -54,17 +54,20 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationCounters;
 
 import java.util.List;
 
 /**
- * The guts of a notification revealed when performing a long press.
+ * The guts of a notification revealed when performing a long press. This also houses the blocking
+ * helper affordance that allows a user to keep/stop notifications after swiping one away.
  */
 public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
     private static final String TAG = "InfoGuts";
 
     private INotificationManager mINotificationManager;
     private PackageManager mPm;
+    private MetricsLogger mMetricsLogger;
 
     private String mPackageName;
     private String mAppName;
@@ -84,17 +87,27 @@
     private OnAppSettingsClickListener mAppSettingsClickListener;
     private NotificationGuts mGutsContainer;
 
-    /** Whether this view is being shown as part of the blocking helper */
+    /** Whether this view is being shown as part of the blocking helper. */
     private boolean mIsForBlockingHelper;
     private boolean mNegativeUserSentiment;
 
-    private OnClickListener mOnKeepShowing = this::closeControls;
+    /** Counter tag that describes how the user exit or quit out of this view. */
+    private String mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+
+    private OnClickListener mOnKeepShowing = v -> {
+        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+        closeControls(v);
+    };
 
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
+        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
         swapContent(false);
     };
 
     private OnClickListener mOnUndo = v -> {
+        // Reset exit counter that we'll log and record an undo event separately (not an exit event)
+        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+        logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
         swapContent(true);
     };
 
@@ -151,6 +164,7 @@
             boolean isUserSentimentNegative)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
+        mMetricsLogger = Dependency.get(MetricsLogger.class);
         mPackageName = pkg;
         mNumUniqueChannelsInRow = numUniqueChannelsInRow;
         mSbn = sbn;
@@ -183,6 +197,8 @@
         bindHeader();
         bindPrompt();
         bindButtons();
+
+        logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_SHOWN);
     }
 
     private void bindHeader() throws RemoteException {
@@ -235,6 +251,8 @@
             final int appUidF = mAppUid;
             settingsButton.setOnClickListener(
                     (View view) -> {
+                        logBlockingHelperCounter(
+                                NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
                         mOnSettingsClickListener.onClick(view,
                                 mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
                                 appUidF);
@@ -269,6 +287,13 @@
         }
     }
 
+    @VisibleForTesting
+    void logBlockingHelperCounter(String counterTag) {
+        if (mIsForBlockingHelper) {
+            mMetricsLogger.count(counterTag, 1);
+        }
+    }
+
     private boolean hasImportanceChanged() {
         return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
     }
@@ -437,25 +462,15 @@
      */
     @VisibleForTesting
     void closeControls(View v) {
-        if (mIsForBlockingHelper) {
-            NotificationBlockingHelperManager manager =
-                    Dependency.get(NotificationBlockingHelperManager.class);
-            manager.dismissCurrentBlockingHelper();
-
-            // Since this won't get a callback via gutsContainer.closeControls, save the new
-            // importance values immediately.
-            saveImportance();
-        } else {
-            int[] parentLoc = new int[2];
-            int[] targetLoc = new int[2];
-            mGutsContainer.getLocationOnScreen(parentLoc);
-            v.getLocationOnScreen(targetLoc);
-            final int centerX = v.getWidth() / 2;
-            final int centerY = v.getHeight() / 2;
-            final int x = targetLoc[0] - parentLoc[0] + centerX;
-            final int y = targetLoc[1] - parentLoc[1] + centerY;
-            mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
-        }
+        int[] parentLoc = new int[2];
+        int[] targetLoc = new int[2];
+        mGutsContainer.getLocationOnScreen(parentLoc);
+        v.getLocationOnScreen(targetLoc);
+        final int centerX = v.getWidth() / 2;
+        final int centerY = v.getHeight() / 2;
+        final int x = targetLoc[0] - parentLoc[0] + centerX;
+        final int y = targetLoc[1] - parentLoc[1] + centerY;
+        mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
     }
 
     @Override
@@ -480,6 +495,7 @@
         if (save) {
             saveImportance();
         }
+        logBlockingHelperCounter(mExitReasonCounter);
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java
new file mode 100644
index 0000000..9a12e8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+/**
+ * Constants for counter tags for Notification-related actions/views.
+ */
+public class NotificationCounters {
+    /** Counter tag for notification dismissal. */
+    public static final String NOTIFICATION_DISMISSED = "notification_dismissed";
+
+    /** Counter tag for when the blocking helper is shown to the user. */
+    public static final String BLOCKING_HELPER_SHOWN = "blocking_helper_shown";
+    /** Counter tag for when the blocking helper is dismissed via a miscellaneous interaction. */
+    public static final String BLOCKING_HELPER_DISMISSED = "blocking_helper_dismissed";
+    /** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
+    public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
+            "blocking_helper_stop_notifications";
+    /** Counter tag for when the user hits 'keep showing' in the blocking helper. */
+    public static final String BLOCKING_HELPER_KEEP_SHOWING =
+            "blocking_helper_keep_showing";
+    /**
+     * Counter tag for when the user hits undo in context of the blocking helper - this can happen
+     * multiple times per view.
+     */
+    public static final String BLOCKING_HELPER_UNDO = "blocking_helper_undo";
+    /** Counter tag for when the user hits the notification settings icon in the blocking helper. */
+    public static final String BLOCKING_HELPER_NOTIF_SETTINGS =
+            "blocking_helper_notif_settings";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 264f574..4b66ee5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -55,6 +55,7 @@
     private final UnlockMethodCache mUnlockMethodCache;
     private AccessibilityController mAccessibilityController;
     private boolean mHasFingerPrintIcon;
+    private boolean mHasFaceUnlockIcon;
     private int mDensity;
 
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
@@ -130,6 +131,7 @@
         }
         int state = getState();
         boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+        mHasFaceUnlockIcon = state == STATE_FACE_UNLOCK;
         boolean useAdditionalPadding = anyFingerprintIcon;
         boolean trustHidden = anyFingerprintIcon;
         if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
@@ -179,6 +181,11 @@
             setRestingAlpha(
                     anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
             setImageDrawable(icon, false);
+            if (mHasFaceUnlockIcon) {
+                announceForAccessibility(getContext().getString(
+                    R.string.accessibility_scanning_face));
+            }
+
             mHasFingerPrintIcon = anyFingerprintIcon;
             if (animation != null && isAnim) {
                 animation.forceAnimationOnUI();
@@ -228,6 +235,11 @@
             info.addAction(unlock);
             info.setHintText(getContext().getString(
                     R.string.accessibility_waiting_for_fingerprint));
+        } else if (mHasFaceUnlockIcon){
+            //Avoid 'button' to be spoken for scanning face
+            info.setClassName(LockIcon.class.getName());
+            info.setContentDescription(getContext().getString(
+                R.string.accessibility_scanning_face));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b650944..8bb73da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -199,6 +199,7 @@
     private ValueAnimator mQsSizeChangeAnimator;
 
     private boolean mShowEmptyShadeView;
+    private boolean mShowDndView;
 
     private boolean mQsScrimEnabled = true;
     private boolean mLastAnnouncementWasQuickSettings;
@@ -1599,8 +1600,8 @@
         // When only empty shade view is visible in QS collapsed state, simulate that we would have
         // it in expanded QS state as well so we don't run into troubles when fading the view in/out
         // and expanding/collapsing the whole panel from/to quick settings.
-        if (mNotificationStackScroller.getNotGoneChildCount() == 0
-                && mShowEmptyShadeView) {
+        if ((mNotificationStackScroller.getNotGoneChildCount() == 0
+                && mShowEmptyShadeView) || mShowDndView) {
             notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
         }
         int maxQsHeight = mQsMaxExpansionHeight;
@@ -2243,13 +2244,17 @@
         return mDozing;
     }
 
+    public void showDndView(boolean dndViewVisible) {
+        mShowDndView = dndViewVisible;
+        mNotificationStackScroller.updateDndView(mShowDndView && !mQsExpanded);
+    }
+
     public void showEmptyShadeView(boolean emptyShadeViewVisible) {
         mShowEmptyShadeView = emptyShadeViewVisible;
         updateEmptyShadeView();
     }
 
     private void updateEmptyShadeView() {
-
         // Hide "No notifications" in QS.
         mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ff0adb6..57a3556 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,6 +20,7 @@
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -168,6 +169,7 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.qs.QSFragment;
@@ -188,6 +190,7 @@
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -413,7 +416,7 @@
     protected NotificationViewHierarchyManager mViewHierarchyManager;
     protected AppOpsListener mAppOpsListener;
     protected KeyguardViewMediator mKeyguardViewMediator;
-    private ZenModeController mZenController;
+    protected ZenModeController mZenController;
 
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -878,6 +881,7 @@
         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
 
         inflateEmptyShadeView();
+        inflateDndView();
         inflateFooterView();
 
         mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
@@ -1145,6 +1149,7 @@
     protected void reevaluateStyles() {
         inflateFooterView();
         updateFooter();
+        inflateDndView();
         inflateEmptyShadeView();
         updateEmptyShadeView();
     }
@@ -1166,6 +1171,19 @@
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
     }
 
+    private void inflateDndView() {
+        if (mStackScroller == null) {
+            return;
+        }
+        mDndView = (DndSuppressingNotificationsView) LayoutInflater.from(mContext).inflate(
+                R.layout.status_bar_dnd_suppressing_notifications, mStackScroller, false);
+        mDndView.setOnContentClickListener(v -> {
+            Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+            startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        });
+        mStackScroller.setDndView(mDndView);
+    }
+
     private void inflateFooterView() {
         if (mStackScroller == null) {
             return;
@@ -1460,9 +1478,11 @@
     @VisibleForTesting
     protected void updateFooter() {
         boolean showFooterView = mState != StatusBarState.KEYGUARD
+                && !areNotificationsHidden()
                 && mEntryManager.getNotificationData().getActiveNotifications().size() != 0
                 && !mRemoteInputManager.getController().isRemoteInputActive();
         boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
+                && !areNotificationsHidden()
                 && hasActiveClearableNotifications();
 
         mStackScroller.updateFooterView(showFooterView, showDismissView);
@@ -1485,10 +1505,13 @@
         return false;
     }
 
-    private void updateEmptyShadeView() {
-        boolean showEmptyShadeView =
-                mState != StatusBarState.KEYGUARD &&
-                        mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+    @VisibleForTesting
+    protected void updateEmptyShadeView() {
+        boolean showDndView = mState != StatusBarState.KEYGUARD && areNotificationsHidden();
+        boolean showEmptyShadeView = !showDndView
+                && mState != StatusBarState.KEYGUARD
+                && mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+        mNotificationPanel.showDndView(showDndView);
         mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
     }
 
@@ -4988,6 +5011,7 @@
     protected NotificationShelf mNotificationShelf;
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
+    protected DndSuppressingNotificationsView mDndView;
 
     protected AssistManager mAssistManager;
 
@@ -5472,6 +5496,11 @@
                     mStackScroller.getChildCount() - offsetFromEnd++);
         }
 
+        if (mDndView != null) {
+            mStackScroller.changeViewPosition(mDndView,
+                    mStackScroller.getChildCount() - offsetFromEnd++);
+        }
+
         mStackScroller.changeViewPosition(mEmptyShadeView,
                 mStackScroller.getChildCount() - offsetFromEnd++);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5275e27..eeaa6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -81,6 +81,7 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
@@ -236,6 +237,7 @@
     protected boolean mScrollingEnabled;
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
+    protected DndSuppressingNotificationsView mDndView;
     private boolean mDismissAllInProgress;
     private boolean mFadeNotificationsOnDismiss;
 
@@ -1006,7 +1008,8 @@
     private float getAppearEndPosition() {
         int appearPosition;
         int notGoneChildCount = getNotGoneChildCount();
-        if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
+        if ((mEmptyShadeView.getVisibility() == GONE && mDndView.getVisibility() == GONE)
+                && notGoneChildCount != 0) {
             if (isHeadsUpTransition()
                     || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
                 appearPosition = getTopHeadsUpPinnedHeight();
@@ -1016,6 +1019,8 @@
                     appearPosition += mShelf.getIntrinsicHeight();
                 }
             }
+        } else if (mEmptyShadeView.getVisibility() == GONE) {
+            appearPosition = mDndView.getHeight();
         } else {
             appearPosition = mEmptyShadeView.getHeight();
         }
@@ -2608,19 +2613,6 @@
         return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
     }
 
-    public int getFirstChildIntrinsicHeight() {
-        final ExpandableView firstChild = getFirstChildNotGone();
-        int firstChildMinHeight = firstChild != null
-                ? firstChild.getIntrinsicHeight()
-                : mEmptyShadeView != null
-                        ? mEmptyShadeView.getIntrinsicHeight()
-                        : mCollapsedSize;
-        if (mOwnScrollY > 0) {
-            firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
-        }
-        return firstChildMinHeight;
-    }
-
     public float getTopPaddingOverflow() {
         return mTopPaddingOverflow;
     }
@@ -3918,6 +3910,7 @@
         final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor);
         mFooterView.setTextColor(textColor);
         mEmptyShadeView.setTextColor(textColor);
+        mDndView.setColor(textColor);
     }
 
     public void goToFullShade(long delay) {
@@ -3925,6 +3918,7 @@
             mFooterView.setInvisible();
         }
         mEmptyShadeView.setInvisible();
+        mDndView.setInvisible();
         mGoToFullShadeNeedsAnimation = true;
         mGoToFullShadeDelay = delay;
         mNeedsAnimation = true;
@@ -4076,25 +4070,39 @@
         int newVisibility = visible ? VISIBLE : GONE;
 
         boolean changedVisibility = oldVisibility != newVisibility;
-        if (changedVisibility || newVisibility != GONE) {
+        if (changedVisibility) {
             if (newVisibility != GONE) {
-                int oldText = mEmptyShadeView.getTextResource();
-                int newText;
-                if (mStatusBar.areNotificationsHidden()) {
-                    newText = R.string.dnd_suppressing_shade_text;
-                } else {
-                    newText = R.string.empty_shade_text;
-                }
-                if (changedVisibility || !Objects.equals(oldText, newText)) {
-                    mEmptyShadeView.setText(newText);
-                    showFooterView(mEmptyShadeView);
-                }
+                showFooterView(mEmptyShadeView);
             } else {
                 hideFooterView(mEmptyShadeView, true);
             }
         }
     }
 
+    public void setDndView(DndSuppressingNotificationsView dndView) {
+        int index = -1;
+        if (mDndView != null) {
+            index = indexOfChild(mDndView);
+            removeView(mDndView);
+        }
+        mDndView = dndView;
+        addView(mDndView, index);
+    }
+
+    public void updateDndView(boolean visible) {
+        int oldVisibility = mDndView.willBeGone() ? GONE : mDndView.getVisibility();
+        int newVisibility = visible ? VISIBLE : GONE;
+
+        boolean changedVisibility = oldVisibility != newVisibility;
+        if (changedVisibility) {
+            if (newVisibility != GONE) {
+                showFooterView(mDndView);
+            } else {
+                hideFooterView(mDndView, true);
+            }
+        }
+    }
+
     public void updateFooterView(boolean visible, boolean showDismissView) {
         if (mFooterView == null) {
             return;
@@ -4119,10 +4127,16 @@
         } else {
             footerView.setInvisible();
         }
-        footerView.setVisibility(VISIBLE);
-        footerView.setWillBeGone(false);
-        updateContentHeight();
-        notifyHeightChangeListener(footerView);
+        Runnable onShowFinishRunnable = new Runnable() {
+            @Override
+            public void run() {
+                footerView.setVisibility(VISIBLE);
+                footerView.setWillBeGone(false);
+                updateContentHeight();
+                notifyHeightChangeListener(footerView);
+            }
+        };
+        footerView.performVisibilityAnimation(true, onShowFinishRunnable);
     }
 
     private void hideFooterView(StackScrollerDecorView footerView, boolean isButtonVisible) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index b0530c8..65fd7f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -33,9 +33,12 @@
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -44,7 +47,6 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -52,7 +54,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
-import android.os.Looper;
+import android.os.IBinder;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -65,6 +67,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -100,7 +103,7 @@
     private StatusBarNotification mSbn;
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
-    private Looper mLooper;
+    @Mock private MetricsLogger mMetricsLogger;
     @Mock private INotificationManager mMockINotificationManager;
     @Mock private PackageManager mMockPackageManager;
     @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@@ -112,6 +115,7 @@
                 mBlockingHelperManager);
         mTestableLooper = TestableLooper.get(this);
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         // Inflate the layout
         final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
         mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
@@ -301,6 +305,24 @@
     }
 
     @Test
+    public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
+        mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
+    }
+
+    @Test
+    public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
+        // Bind notification logs an event, so this counts as one invocation for the metrics logger.
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
+                true);
+        mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+        verify(mMetricsLogger, times(2)).count(anyString(), anyInt());
+    }
+
+    @Test
     public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -471,6 +493,13 @@
                 false /* isNonblockable */, true /* isForBlockingHelper */,
                 true /* isUserSentimentNegative */);
 
+        NotificationGuts guts = spy(new NotificationGuts(mContext, null));
+        when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
+        doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
+        doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
+        guts.setGutsContent(mNotificationInfo);
+        mNotificationInfo.setGutsParent(guts);
+
         mNotificationInfo.findViewById(R.id.keep).performClick();
 
         verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
@@ -495,6 +524,9 @@
                 false /* isNonblockable */,
                 true /* isForBlockingHelper */,
                 false /* isUserSentimentNegative */);
+        NotificationGuts guts = mock(NotificationGuts.class);
+        doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+        mNotificationInfo.setGutsParent(guts);
 
         mNotificationInfo.closeControls(mNotificationInfo);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 37e0005..41cf869 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -78,6 +78,7 @@
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.AppOpsListener;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.FooterViewButton;
@@ -103,6 +104,7 @@
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
@@ -132,6 +134,7 @@
     @Mock private ScrimController mScrimController;
     @Mock private ArrayList<Entry> mNotificationList;
     @Mock private FingerprintUnlockController mFingerprintUnlockController;
+    @Mock private ZenModeController mZenController;
     @Mock private NotificationData mNotificationData;
 
     // Mock dependencies:
@@ -163,6 +166,7 @@
         mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
         mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
         mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class));
+        mDependency.injectTestDependency(ZenModeController.class, mZenController);
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -213,7 +217,7 @@
                 mRemoteInputManager, mock(NotificationGroupManager.class),
                 mock(FalsingManager.class), mock(StatusBarWindowManager.class),
                 mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
-                mock(NotificationShelf.class), mLockscreenUserManager,
+                mock(NotificationShelf.class), mLockscreenUserManager, mZenController,
                 mock(CommandQueue.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
@@ -676,6 +680,60 @@
     }
 
     @Test
+    public void testDNDView_atEnd() {
+        // add footer
+        mStatusBar.reevaluateStyles();
+
+        // add notification
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        mStackScroller.addContainerView(row);
+
+        mStatusBar.onUpdateRowStates();
+
+        // move dnd view to end
+        verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+        verify(mStackScroller).changeViewPosition(any(DndSuppressingNotificationsView.class),
+                eq(-2 /* end */));
+    }
+
+    @Test
+    public void updateEmptyShade_nonNotificationsDndOff() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+        assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+
+        mStatusBar.updateEmptyShadeView();
+        verify(mNotificationPanelView).showDndView(false);
+        verify(mNotificationPanelView).showEmptyShadeView(true);
+    }
+
+    @Test
+    public void updateEmptyShade_noNotificationsDndOn() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+        assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+        when(mZenController.areNotificationsHiddenInShade()).thenReturn(true);
+
+        mStatusBar.updateEmptyShadeView();
+        verify(mNotificationPanelView).showDndView(true);
+        verify(mNotificationPanelView).showEmptyShadeView(false);
+    }
+
+    @Test
+    public void updateEmptyShade_yesNotificationsDndOff() {
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+        ArrayList<Entry> entries = new ArrayList<>();
+        entries.add(mock(Entry.class));
+        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+        assertEquals(1, mEntryManager.getNotificationData().getActiveNotifications().size());
+        when(mZenController.areNotificationsHiddenInShade()).thenReturn(false);
+
+        mStatusBar.updateEmptyShadeView();
+        verify(mNotificationPanelView).showDndView(false);
+        verify(mNotificationPanelView).showEmptyShadeView(false);
+    }
+
+    @Test
     public void testSetState_changesIsFullScreenUserSwitcherState() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         assertFalse(mStatusBar.isFullScreenUserSwitcherState());
@@ -721,6 +779,7 @@
                 DozeScrimController dozeScrimController,
                 NotificationShelf notificationShelf,
                 NotificationLockscreenUserManager notificationLockscreenUserManager,
+                ZenModeController zenController,
                 CommandQueue commandQueue) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
@@ -749,6 +808,7 @@
             mDozeScrimController = dozeScrimController;
             mNotificationShelf = notificationShelf;
             mLockscreenUserManager = notificationLockscreenUserManager;
+            mZenController = zenController;
             mCommandQueue = commandQueue;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index eeb4209..3d17ec4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -34,6 +35,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.TestableDependency;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.FooterView;
 import com.android.systemui.statusbar.NotificationBlockingHelperManager;
@@ -69,6 +71,7 @@
     @Mock private NotificationGroupManager mGroupManager;
     @Mock private ExpandHelper mExpandHelper;
     @Mock private EmptyShadeView mEmptyShadeView;
+    @Mock private DndSuppressingNotificationsView mDndView;
 
     @Before
     @UiThreadTest
@@ -86,6 +89,7 @@
         mStackScroller.setHeadsUpManager(mHeadsUpManager);
         mStackScroller.setGroupManager(mGroupManager);
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
+        mStackScroller.setDndView(mDndView);
 
         // Stub out functionality that isn't necessary to test.
         doNothing().when(mBar)
@@ -120,40 +124,6 @@
     }
 
     @Test
-    public void updateEmptyView_dndSuppressing() {
-        when(mEmptyShadeView.willBeGone()).thenReturn(true);
-        when(mBar.areNotificationsHidden()).thenReturn(true);
-
-        mStackScroller.updateEmptyShadeView(true);
-
-        verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
-    }
-
-    @Test
-    public void updateEmptyView_dndNotSuppressing() {
-        mStackScroller.setEmptyShadeView(mEmptyShadeView);
-        when(mEmptyShadeView.willBeGone()).thenReturn(true);
-        when(mBar.areNotificationsHidden()).thenReturn(false);
-
-        mStackScroller.updateEmptyShadeView(true);
-
-        verify(mEmptyShadeView).setText(R.string.empty_shade_text);
-    }
-
-    @Test
-    public void updateEmptyView_noNotificationsToDndSuppressing() {
-        mStackScroller.setEmptyShadeView(mEmptyShadeView);
-        when(mEmptyShadeView.willBeGone()).thenReturn(true);
-        when(mBar.areNotificationsHidden()).thenReturn(false);
-        mStackScroller.updateEmptyShadeView(true);
-        verify(mEmptyShadeView).setText(R.string.empty_shade_text);
-
-        when(mBar.areNotificationsHidden()).thenReturn(true);
-        mStackScroller.updateEmptyShadeView(true);
-        verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
-    }
-
-    @Test
     @UiThreadTest
     public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
         mStackScroller.setExpandedHeight(0f);
@@ -173,7 +143,7 @@
 
         mStackScroller.updateFooterView(true, false);
 
-        verify(view).setVisibility(View.VISIBLE);
+        verify(view).performVisibilityAnimation(eq(true), any());
         verify(view).performSecondaryVisibilityAnimation(false);
     }
 
@@ -186,7 +156,7 @@
 
         mStackScroller.updateFooterView(true, true);
 
-        verify(view).setVisibility(View.VISIBLE);
+        verify(view).performVisibilityAnimation(eq(true), any());
         verify(view).performSecondaryVisibilityAnimation(true);
     }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e33ef1f..7dd85ba 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5717,6 +5717,29 @@
     // OS: P
     SETTINGS_ZEN_NOTIFICATIONS = 1400;
 
+    // An event category for slices.
+    // OPEN: Slice became visible.
+    // CLOSE: Slice became invisible.
+    // ACTION: Slice was tapped.
+    SLICE = 1401;
+
+    // The authority part of the slice URI
+    FIELD_SLICE_AUTHORITY = 1402;
+
+    // The path part of the slice URI
+    FIELD_SLICE_PATH = 1403;
+
+    // The authority part of the subslice URI
+    FIELD_SUBSLICE_AUTHORITY = 1404;
+
+    // The path part of the subslice URI
+    FIELD_SUBSLICE_PATH = 1405;
+
+    // OPEN: DND onboarding activity > don't update button
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 821cca1..44edabc 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -421,7 +421,7 @@
 
                 // after the app's agent runs to handle its private filesystem
                 // contents, back up any OBB content it has on its behalf.
-                if (mIncludeObbs) {
+                if (mIncludeObbs && !isSharedStorage) {
                     boolean obbOkay = obbConnection.backupObbs(pkg, out);
                     if (!obbOkay) {
                         throw new RuntimeException("Failure writing OBB stack for " + pkg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 193d3f4..a8e63f6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5049,9 +5049,20 @@
     public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
+                resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
+                true /*validateIncomingUser*/);
+    }
+
+    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
+            boolean validateIncomingUser) {
         enforceNotIsolatedCaller("startActivity");
-        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+
+        userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
+                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
+
         // TODO: Switch to user app stacks here.
         return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                 .setCaller(caller)
@@ -26344,6 +26355,16 @@
         }
 
         @Override
+        public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
+                Intent intent, Bundle options, int userId) {
+            return ActivityManagerService.this.startActivityAsUser(
+                    caller, callerPacakge, intent,
+                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId,
+                    false /*validateIncomingUser*/);
+        }
+
+        @Override
         public int getUidProcessState(int uid) {
             return getUidState(uid);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 548290e..4ace689 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1315,10 +1315,6 @@
         return aInfo;
     }
 
-    ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
-        return resolveIntent(intent, resolvedType, userId, 0, Binder.getCallingUid());
-    }
-
     ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,
             int filterCallingUid) {
         synchronized (mService) {
@@ -1330,9 +1326,19 @@
                             || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
                     modifiedFlags |= PackageManager.MATCH_INSTANT;
                 }
-                return mService.getPackageManagerInternalLocked().resolveIntent(
-                        intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
 
+                // In order to allow cross-profile lookup, we clear the calling identity here.
+                // Note the binder identity won't affect the result, but filterCallingUid will.
+
+                // Cross-user/profile call check are done at the entry points
+                // (e.g. AMS.startActivityAsUser).
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    return mService.getPackageManagerInternalLocked().resolveIntent(
+                            intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             } finally {
                 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 31ccf35..5e29d10 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -233,7 +233,7 @@
      * ensures {@code targetUserId} is a real user ID and not a special user ID such as
      * {@link android.os.UserHandle#USER_ALL}, etc.
      */
-    private int checkTargetUser(int targetUserId, boolean validateIncomingUser,
+    int checkTargetUser(int targetUserId, boolean validateIncomingUser,
             int realCallingPid, int realCallingUid, String reason) {
         if (validateIncomingUser) {
             return mService.mUserController.handleIncomingUser(realCallingPid, realCallingUid,
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 5b6b508..8c3ff34 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -203,7 +203,7 @@
         mResolvedType = null;
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
-        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
         return true;
     }
@@ -223,9 +223,11 @@
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
         if (parent != null) {
-            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
+                    mRealCallingUid);
         } else {
-            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
+                    mRealCallingUid);
         }
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
         return true;
@@ -244,7 +246,8 @@
         final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
                 .setPackage(suspendingPackage);
         final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
-        final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
+        final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId,
+                0, mRealCallingUid);
         if (resolvedInfo != null && resolvedInfo.activityInfo != null
                 && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
             moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
@@ -276,7 +279,7 @@
         mCallingPid = mRealCallingPid;
         mCallingUid = mRealCallingUid;
         mResolvedType = null;
-        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
         return true;
     }
@@ -309,7 +312,7 @@
         }
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
-        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
         return true;
     }
@@ -362,7 +365,7 @@
         mCallingUid = mRealCallingUid;
         mResolvedType = null;
 
-        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
         return true;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7ff7d9a..fb4107c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -791,7 +791,7 @@
                 callingUid = realCallingUid;
                 callingPid = realCallingPid;
 
-                rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+                rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0, realCallingUid);
                 aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                         null /*profilerInfo*/);
 
@@ -952,6 +952,9 @@
         mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
         boolean componentSpecified = intent.getComponent() != null;
 
+        final int realCallingPid = Binder.getCallingPid();
+        final int realCallingUid = Binder.getCallingUid();
+
         // Save a copy in case ephemeral needs it
         final Intent ephemeralIntent = new Intent(intent);
         // Don't modify the client's object!
@@ -969,7 +972,8 @@
             componentSpecified = false;
         }
 
-        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+                0 /* matchFlags */, realCallingUid);
         if (rInfo == null) {
             UserInfo userInfo = mSupervisor.getUserInfo(userId);
             if (userInfo != null && userInfo.isManagedProfile()) {
@@ -991,7 +995,7 @@
                     rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
                             PackageManager.MATCH_DIRECT_BOOT_AWARE
                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                            Binder.getCallingUid());
+                            realCallingUid);
                 }
             }
         }
@@ -999,8 +1003,6 @@
         ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
 
         synchronized (mService) {
-            final int realCallingPid = Binder.getCallingPid();
-            final int realCallingUid = Binder.getCallingUid();
             int callingPid;
             if (callingUid >= 0) {
                 callingPid = -1;
@@ -1073,7 +1075,8 @@
                         callingUid = Binder.getCallingUid();
                         callingPid = Binder.getCallingPid();
                         componentSpecified = true;
-                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
+                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
+                                0 /* matchFlags */, realCallingUid);
                         aInfo = rInfo != null ? rInfo.activityInfo : null;
                         if (aInfo != null) {
                             aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ec3949f..b68ef11 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
@@ -710,7 +711,7 @@
                 StatusBarNotification sbn = r.sbn;
                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
-                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+                        FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
                         REASON_CLICK, nv.rank, nv.count, null);
                 nv.recycle();
                 reportUserInteraction(r);
@@ -754,7 +755,7 @@
                 }
             }
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
-                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                    Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
                     true, userId, REASON_CANCEL, nv.rank, nv.count,null);
             nv.recycle();
         }
@@ -985,7 +986,7 @@
                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
                             record.sbn.getPackageName(), record.sbn.getTag(),
                             record.sbn.getId(), 0,
-                            Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
+                            FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
                             REASON_TIMEOUT, null);
                 }
             }
@@ -2084,7 +2085,7 @@
             // Don't allow client applications to cancel foreground service notis or autobundled
             // summaries.
             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
-                    (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
+                    (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
         }
@@ -2099,7 +2100,7 @@
             // Calling from user space, don't allow the canceling of actively
             // running foreground services.
             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
-                    pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
+                    pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
                     REASON_APP_CANCEL_ALL, null);
         }
 
@@ -2685,7 +2686,7 @@
         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
-                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                    Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
                     true,
                     userId, REASON_LISTENER_CANCEL, info);
         }
@@ -3876,7 +3877,9 @@
                     for (int j = 0; j < listenerSize; j++) {
                         if (i > 0) pw.print(',');
                         final ManagedServiceInfo listener = listeners.valueAt(i);
-                        pw.print(listener.component);
+                        if (listener != null) {
+                            pw.print(listener.component);
+                        }
                     }
                 }
                 pw.println(')');
@@ -3962,7 +3965,7 @@
             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
             sbn.getNotification().flags =
-                    (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
+                    (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
             mRankingHelper.sort(mNotificationList);
             mListeners.notifyPostedLocked(r, r);
         }
@@ -4048,7 +4051,7 @@
         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
         r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
 
-        if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
+        if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0
                 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
                 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
             // Increase the importance of foreground service notifications unless the user had an
@@ -4429,7 +4432,7 @@
                         mUsageStats.registerUpdatedByApp(r, old);
                         // Make sure we don't lose the foreground service state.
                         notification.flags |=
-                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+                                old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
                         r.isUpdate = true;
                         r.setInterruptive(isVisuallyInterruptive(old, r));
                     }
@@ -4438,7 +4441,7 @@
 
                     // Ensure if this is a foreground service that the proper additional
                     // flags are set.
-                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+                    if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
                         notification.flags |= Notification.FLAG_ONGOING_EVENT
                                 | Notification.FLAG_NO_CLEAR;
                     }
@@ -4506,6 +4509,13 @@
         if (oldN.extras == null || newN.extras == null) {
             return false;
         }
+
+        // Ignore visual interruptions from foreground services because users
+        // consider them one 'session'. Count them for everything else.
+        if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
+            return false;
+        }
+
         if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
                 newN.extras.get(Notification.EXTRA_TITLE))) {
             return true;
@@ -5805,7 +5815,7 @@
             final StatusBarNotification childSbn = childR.sbn;
             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
                     childR.getGroupKey().equals(parentNotification.getGroupKey())
-                    && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
+                    && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 156f702..658c7f1 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -173,18 +173,6 @@
         }
     }
 
-    public boolean shouldSuppressWhenScreenOff() {
-        synchronized (mConfig) {
-            return !mConfig.allowWhenScreenOff;
-        }
-    }
-
-    public boolean shouldSuppressWhenScreenOn() {
-        synchronized (mConfig) {
-            return !mConfig.allowWhenScreenOn;
-        }
-    }
-
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
     }
@@ -592,14 +580,12 @@
             return;
         }
         pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
-                + "messages=%b,messagesFrom=%s,"
-                + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
+                + "messages=%b,messagesFrom=%s,events=%b,reminders=%b)\n",
                 config.allowAlarms, config.allowMedia, config.allowSystem,
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
                 config.allowRepeatCallers, config.allowMessages,
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
-                config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
-                config.allowWhenScreenOn);
+                config.allowEvents, config.allowReminders);
         pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
@@ -1185,7 +1171,7 @@
 
     private void showZenUpgradeNotification(int zen) {
         final boolean showNotification = mIsBootComplete
-                && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+                && zen != Global.ZEN_MODE_OFF
                 && Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
 
@@ -1204,17 +1190,20 @@
                 mContext.getResources().getString(R.string.global_action_settings));
         int title = R.string.zen_upgrade_notification_title;
         int content = R.string.zen_upgrade_notification_content;
+        int drawable = R.drawable.ic_zen_24dp;
         if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
                 getNotificationPolicy().suppressedVisualEffects)) {
             title = R.string.zen_upgrade_notification_visd_title;
             content = R.string.zen_upgrade_notification_visd_content;
+            drawable = R.drawable.ic_dnd_block_notifications;
         }
+
         Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
         onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
                 .setAutoCancel(true)
                 .setSmallIcon(R.drawable.ic_settings_24dp)
-                .setLargeIcon(Icon.createWithResource(mContext, R.drawable.ic_zen_24dp))
+                .setLargeIcon(Icon.createWithResource(mContext, drawable))
                 .setContentTitle(mContext.getResources().getString(title))
                 .setContentText(mContext.getResources().getString(content))
                 .setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 595de9e..feac8e6 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.IApplicationThread;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -560,7 +561,7 @@
         }
 
         @Override
-        public void startActivityAsUser(String callingPackage,
+        public void startActivityAsUser(IApplicationThread caller, String callingPackage,
                 ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
             if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
@@ -574,6 +575,8 @@
                     | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
             launchIntent.setPackage(component.getPackageName());
 
+            boolean canLaunch = false;
+
             final int callingUid = injectBinderCallingUid();
             long ident = Binder.clearCallingIdentity();
             try {
@@ -604,35 +607,42 @@
                         // this component so ok to launch.
                         launchIntent.setPackage(null);
                         launchIntent.setComponent(component);
-                        mContext.startActivityAsUser(launchIntent, opts, user);
-                        return;
+                        canLaunch = true;
+                        break;
                     }
                 }
-                throw new SecurityException("Attempt to launch activity without "
-                        + " category Intent.CATEGORY_LAUNCHER " + component);
+                if (!canLaunch) {
+                    throw new SecurityException("Attempt to launch activity without "
+                            + " category Intent.CATEGORY_LAUNCHER " + component);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
+            mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+                    launchIntent, opts, user.getIdentifier());
         }
 
         @Override
-        public void showAppDetailsAsUser(String callingPackage, ComponentName component,
+        public void showAppDetailsAsUser(IApplicationThread caller,
+                String callingPackage, ComponentName component,
                 Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
             if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
                 return;
             }
 
+            final Intent intent;
             long ident = Binder.clearCallingIdentity();
             try {
                 String packageName = component.getPackageName();
-                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                         Uri.fromParts("package", packageName, null));
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                 intent.setSourceBounds(sourceBounds);
-                mContext.startActivityAsUser(intent, opts, user);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
+            mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+                    intent, opts, user.getIdentifier());
         }
 
         /** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 144f289..681b0c9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -22462,9 +22462,13 @@
         }
         final String volumeUuid = pkg.volumeUuid;
         final String packageName = pkg.packageName;
-        final ApplicationInfo app = (ps == null)
+
+        ApplicationInfo app = (ps == null)
                 ? pkg.applicationInfo
                 : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
+        if (app == null) {
+            app = pkg.applicationInfo;
+        }
 
         final int appId = UserHandle.getAppId(app.uid);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index eb1c997..58f5898 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -528,7 +529,7 @@
                 PKG, new ParceledListSlice(Arrays.asList(channel)));
 
         final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         waitForIdle();
@@ -557,7 +558,7 @@
                 mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
 
         final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         waitForIdle();
@@ -601,7 +602,7 @@
         mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
 
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         waitForIdle();
@@ -759,7 +760,7 @@
     @Test
     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
@@ -773,7 +774,7 @@
     @Test
     public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
@@ -901,7 +902,7 @@
     @Test
     public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
-        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
@@ -909,14 +910,14 @@
         waitForIdle();
         StatusBarNotification[] notifs =
                 mBinderService.getActiveNotifications(sbn.getPackageName());
-        assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
+        assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
     }
 
     @Test
     public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
         sbn.getNotification().flags =
-                Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
+                Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
         sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
@@ -937,7 +938,7 @@
                 mTestNotificationChannel, 2, "group", false);
         final NotificationRecord child2 = generateNotificationRecord(
                 mTestNotificationChannel, 3, "group", false);
-        child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         final NotificationRecord newGroup = generateNotificationRecord(
                 mTestNotificationChannel, 4, "group2", false);
         mService.addNotification(parent);
@@ -960,7 +961,7 @@
                 mTestNotificationChannel, 2, "group", false);
         final NotificationRecord child2 = generateNotificationRecord(
                 mTestNotificationChannel, 3, "group", false);
-        child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         final NotificationRecord newGroup = generateNotificationRecord(
                 mTestNotificationChannel, 4, "group2", false);
         mService.addNotification(parent);
@@ -984,7 +985,7 @@
                 mTestNotificationChannel, 2, "group", false);
         final NotificationRecord child2 = generateNotificationRecord(
                 mTestNotificationChannel, 3, "group", false);
-        child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         final NotificationRecord newGroup = generateNotificationRecord(
                 mTestNotificationChannel, 4, "group2", false);
         mService.addNotification(parent);
@@ -2187,7 +2188,6 @@
     @Test
     public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
         final String upgradeXml = "<notification-policy version=\"1\">"
-                + "<zen></zen>"
                 + "<ranking></ranking>"
                 + "<enabled_listeners>"
                 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
@@ -2215,7 +2215,6 @@
     @Test
     public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
         final String preupgradeXml = "<notification-policy version=\"1\">"
-                + "<zen></zen>"
                 + "<ranking></ranking>"
                 + "</notification-policy>";
         mService.readPolicyXml(
@@ -2257,7 +2256,7 @@
                 NotificationChannel.DEFAULT_CHANNEL_ID)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
                 .setPriority(Notification.PRIORITY_MIN);
 
         StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2272,7 +2271,7 @@
         nb = new Notification.Builder(mContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
                 .setPriority(Notification.PRIORITY_MIN);
 
         sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2670,6 +2669,26 @@
     }
 
     @Test
+    public void testVisualDifference_foreground() {
+        Notification.Builder nb1 = new Notification.Builder(mContext, "")
+                .setContentTitle("foo");
+        StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb1.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r1 =
+                new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+        Notification.Builder nb2 = new Notification.Builder(mContext, "")
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
+                .setContentTitle("bar");
+        StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb2.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r2 =
+                new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+        assertFalse(mService.isVisuallyInterruptive(r1, r2));
+    }
+
+    @Test
     public void testVisualDifference_diffTitle() {
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentTitle("foo");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index d846d21..36ec221 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -336,6 +336,90 @@
     }
 
     @Test
+    public void testRemoteViews_layoutChange() {
+        RemoteViews a = mock(RemoteViews.class);
+        when(a.getLayoutId()).thenReturn(234);
+        RemoteViews b = mock(RemoteViews.class);
+        when(b.getLayoutId()).thenReturn(189);
+
+        Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+        Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+    }
+
+    @Test
+    public void testRemoteViews_layoutSame() {
+        RemoteViews a = mock(RemoteViews.class);
+        when(a.getLayoutId()).thenReturn(234);
+        RemoteViews b = mock(RemoteViews.class);
+        when(b.getLayoutId()).thenReturn(234);
+
+        Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+        Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+    }
+
+    @Test
+    public void testRemoteViews_sequenceChange() {
+        RemoteViews a = mock(RemoteViews.class);
+        when(a.getLayoutId()).thenReturn(234);
+        when(a.getSequenceNumber()).thenReturn(1);
+        RemoteViews b = mock(RemoteViews.class);
+        when(b.getLayoutId()).thenReturn(234);
+        when(b.getSequenceNumber()).thenReturn(2);
+
+        Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+        Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+        assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+    }
+
+    @Test
+    public void testRemoteViews_sequenceSame() {
+        RemoteViews a = mock(RemoteViews.class);
+        when(a.getLayoutId()).thenReturn(234);
+        when(a.getSequenceNumber()).thenReturn(1);
+        RemoteViews b = mock(RemoteViews.class);
+        when(b.getLayoutId()).thenReturn(234);
+        when(b.getSequenceNumber()).thenReturn(1);
+
+        Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+        Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+        n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+        n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+        assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+    }
+
+    @Test
     public void testActionsDifferent_null() {
         Notification n1 = new Notification.Builder(mContext, "test")
                 .build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index d02a983..afc1263 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,6 +17,9 @@
 package com.android.server.notification;
 
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertEquals;
@@ -569,8 +572,6 @@
         mZenModeHelperSpy.mConfig.allowMessages = true;
         mZenModeHelperSpy.mConfig.allowEvents = true;
         mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
         mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
         mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
         mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
@@ -593,8 +594,6 @@
         mZenModeHelperSpy.mConfig.allowMessages = true;
         mZenModeHelperSpy.mConfig.allowEvents = true;
         mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
         mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
         mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
         mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -645,6 +644,115 @@
     }
 
     @Test
+    public void testMigrateSuppressedVisualEffects_oneExistsButOff() throws Exception {
+        String xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"false\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+        xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOn=\"false\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+    }
+
+    @Test
+    public void testMigrateSuppressedVisualEffects_bothExistButOff() throws Exception {
+        String xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"false\" visualScreenOn=\"false\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+    }
+
+    @Test
+    public void testMigrateSuppressedVisualEffects_bothExistButOn() throws Exception {
+        String xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"true\" visualScreenOn=\"true\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
+                | SUPPRESSED_EFFECT_LIGHTS
+                | SUPPRESSED_EFFECT_PEEK,
+                mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+        xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"false\" visualScreenOn=\"true\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+        xml = "<zen version=\"6\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"true\" visualScreenOn=\"false\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+
+        parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS,
+                mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+    }
+
+    @Test
     public void testReadXmlResetDefaultRules() throws Exception {
         setupZenConfig();
 
@@ -705,16 +813,6 @@
         setupZenConfigMaintained();
     }
 
-    @Test
-    public void testPolicyReadsSuppressedEffects() {
-        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
-        mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
-
-        NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
-        assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
-    }
-
     private void setupZenConfig() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowAlarms = false;
@@ -725,8 +823,6 @@
         mZenModeHelperSpy.mConfig.allowMessages = true;
         mZenModeHelperSpy.mConfig.allowEvents = true;
         mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
-        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
         mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
         mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
         mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -746,8 +842,6 @@
         assertTrue(mZenModeHelperSpy.mConfig.allowMessages);
         assertTrue(mZenModeHelperSpy.mConfig.allowEvents);
         assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
-        assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOff);
-        assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOn);
         assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
     }
 }