Merge "Avoid crashing when sensors are under stress"
diff --git a/api/current.txt b/api/current.txt
index e363f71..94766a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34676,46 +34676,46 @@
 
   public class Handler {
     ctor public Handler();
-    ctor public Handler(android.os.Handler.Callback);
-    ctor public Handler(android.os.Looper);
-    ctor public Handler(android.os.Looper, android.os.Handler.Callback);
+    ctor public Handler(@Nullable android.os.Handler.Callback);
+    ctor public Handler(@NonNull android.os.Looper);
+    ctor public Handler(@NonNull android.os.Looper, @Nullable android.os.Handler.Callback);
     method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper);
     method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper, @NonNull android.os.Handler.Callback);
-    method public void dispatchMessage(android.os.Message);
-    method public final void dump(android.util.Printer, String);
-    method public final android.os.Looper getLooper();
-    method public String getMessageName(android.os.Message);
-    method public void handleMessage(android.os.Message);
-    method public final boolean hasCallbacks(Runnable);
+    method public void dispatchMessage(@NonNull android.os.Message);
+    method public final void dump(@NonNull android.util.Printer, @NonNull String);
+    method @NonNull public final android.os.Looper getLooper();
+    method @NonNull public String getMessageName(@NonNull android.os.Message);
+    method public void handleMessage(@NonNull android.os.Message);
+    method public final boolean hasCallbacks(@NonNull Runnable);
     method public final boolean hasMessages(int);
-    method public final boolean hasMessages(int, Object);
-    method public final android.os.Message obtainMessage();
-    method public final android.os.Message obtainMessage(int);
-    method public final android.os.Message obtainMessage(int, Object);
-    method public final android.os.Message obtainMessage(int, int, int);
-    method public final android.os.Message obtainMessage(int, int, int, Object);
-    method public final boolean post(Runnable);
-    method public final boolean postAtFrontOfQueue(Runnable);
-    method public final boolean postAtTime(Runnable, long);
-    method public final boolean postAtTime(Runnable, Object, long);
-    method public final boolean postDelayed(Runnable, long);
-    method public final boolean postDelayed(Runnable, Object, long);
-    method public final void removeCallbacks(Runnable);
-    method public final void removeCallbacks(Runnable, Object);
-    method public final void removeCallbacksAndMessages(Object);
+    method public final boolean hasMessages(int, @Nullable Object);
+    method @NonNull public final android.os.Message obtainMessage();
+    method @NonNull public final android.os.Message obtainMessage(int);
+    method @NonNull public final android.os.Message obtainMessage(int, @Nullable Object);
+    method @NonNull public final android.os.Message obtainMessage(int, int, int);
+    method @NonNull public final android.os.Message obtainMessage(int, int, int, @Nullable Object);
+    method public final boolean post(@NonNull Runnable);
+    method public final boolean postAtFrontOfQueue(@NonNull Runnable);
+    method public final boolean postAtTime(@NonNull Runnable, long);
+    method public final boolean postAtTime(@NonNull Runnable, @Nullable Object, long);
+    method public final boolean postDelayed(@NonNull Runnable, long);
+    method public final boolean postDelayed(@NonNull Runnable, @Nullable Object, long);
+    method public final void removeCallbacks(@NonNull Runnable);
+    method public final void removeCallbacks(@NonNull Runnable, @Nullable Object);
+    method public final void removeCallbacksAndMessages(@Nullable Object);
     method public final void removeMessages(int);
-    method public final void removeMessages(int, Object);
+    method public final void removeMessages(int, @Nullable Object);
     method public final boolean sendEmptyMessage(int);
     method public final boolean sendEmptyMessageAtTime(int, long);
     method public final boolean sendEmptyMessageDelayed(int, long);
-    method public final boolean sendMessage(android.os.Message);
-    method public final boolean sendMessageAtFrontOfQueue(android.os.Message);
-    method public boolean sendMessageAtTime(android.os.Message, long);
-    method public final boolean sendMessageDelayed(android.os.Message, long);
+    method public final boolean sendMessage(@NonNull android.os.Message);
+    method public final boolean sendMessageAtFrontOfQueue(@NonNull android.os.Message);
+    method public boolean sendMessageAtTime(@NonNull android.os.Message, long);
+    method public final boolean sendMessageDelayed(@NonNull android.os.Message, long);
   }
 
   public static interface Handler.Callback {
-    method public boolean handleMessage(android.os.Message);
+    method public boolean handleMessage(@NonNull android.os.Message);
   }
 
   public class HandlerThread extends java.lang.Thread {
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index e6c12c7..a039742 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -82,19 +82,19 @@
          * @param msg A {@link android.os.Message Message} object
          * @return True if no further handling is desired
          */
-        public boolean handleMessage(Message msg);
+        boolean handleMessage(@NonNull Message msg);
     }
     
     /**
      * Subclasses must implement this to receive messages.
      */
-    public void handleMessage(Message msg) {
+    public void handleMessage(@NonNull Message msg) {
     }
     
     /**
      * Handle system messages here.
      */
-    public void dispatchMessage(Message msg) {
+    public void dispatchMessage(@NonNull Message msg) {
         if (msg.callback != null) {
             handleCallback(msg);
         } else {
@@ -128,7 +128,7 @@
      *
      * @param callback The callback interface in which to handle messages, or null.
      */
-    public Handler(Callback callback) {
+    public Handler(@Nullable Callback callback) {
         this(callback, false);
     }
 
@@ -137,7 +137,7 @@
      *
      * @param looper The looper, must not be null.
      */
-    public Handler(Looper looper) {
+    public Handler(@NonNull Looper looper) {
         this(looper, null, false);
     }
 
@@ -148,7 +148,7 @@
      * @param looper The looper, must not be null.
      * @param callback The callback interface in which to handle messages, or null.
      */
-    public Handler(Looper looper, Callback callback) {
+    public Handler(@NonNull Looper looper, @Nullable Callback callback) {
         this(looper, callback, false);
     }
 
@@ -189,7 +189,7 @@
      *
      * @hide
      */
-    public Handler(Callback callback, boolean async) {
+    public Handler(@Nullable Callback callback, boolean async) {
         if (FIND_POTENTIAL_LEAKS) {
             final Class<? extends Handler> klass = getClass();
             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
@@ -229,7 +229,7 @@
      *
      * @hide
      */
-    public Handler(Looper looper, Callback callback, boolean async) {
+    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
         mLooper = looper;
         mQueue = looper.mQueue;
         mCallback = callback;
@@ -289,7 +289,8 @@
     }
 
     /** {@hide} */
-    public String getTraceName(Message message) {
+    @NonNull
+    public String getTraceName(@NonNull Message message) {
         final StringBuilder sb = new StringBuilder();
         sb.append(getClass().getName()).append(": ");
         if (message.callback != null) {
@@ -308,7 +309,8 @@
      *  
      * @param message The message whose name is being queried 
      */
-    public String getMessageName(Message message) {
+    @NonNull
+    public String getMessageName(@NonNull Message message) {
         if (message.callback != null) {
             return message.callback.getClass().getName();
         }
@@ -320,6 +322,7 @@
      * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
      *  If you don't want that facility, just call Message.obtain() instead.
      */
+    @NonNull
     public final Message obtainMessage()
     {
         return Message.obtain(this);
@@ -331,6 +334,7 @@
      * @param what Value to assign to the returned Message.what field.
      * @return A Message from the global message pool.
      */
+    @NonNull
     public final Message obtainMessage(int what)
     {
         return Message.obtain(this, what);
@@ -345,8 +349,8 @@
      * @param obj Value to assign to the returned Message.obj field.
      * @return A Message from the global message pool.
      */
-    public final Message obtainMessage(int what, Object obj)
-    {
+    @NonNull
+    public final Message obtainMessage(int what, @Nullable Object obj) {
         return Message.obtain(this, what, obj);
     }
 
@@ -359,6 +363,7 @@
      * @param arg2 Value to assign to the returned Message.arg2 field.
      * @return A Message from the global message pool.
      */
+    @NonNull
     public final Message obtainMessage(int what, int arg1, int arg2)
     {
         return Message.obtain(this, what, arg1, arg2);
@@ -374,8 +379,8 @@
      * @param obj Value to assign to the returned Message.obj field.
      * @return A Message from the global message pool.
      */
-    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
-    {
+    @NonNull
+    public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
         return Message.obtain(this, what, arg1, arg2, obj);
     }
 
@@ -390,8 +395,7 @@
      *         message queue.  Returns false on failure, usually because the
      *         looper processing the message queue is exiting.
      */
-    public final boolean post(Runnable r)
-    {
+    public final boolean post(@NonNull Runnable r) {
        return  sendMessageDelayed(getPostMessage(r), 0);
     }
     
@@ -413,8 +417,7 @@
      *         the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public final boolean postAtTime(Runnable r, long uptimeMillis)
-    {
+    public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
         return sendMessageAtTime(getPostMessage(r), uptimeMillis);
     }
     
@@ -440,8 +443,8 @@
      *         
      * @see android.os.SystemClock#uptimeMillis
      */
-    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
-    {
+    public final boolean postAtTime(
+            @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
         return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
     }
     
@@ -464,8 +467,7 @@
      *         if the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public final boolean postDelayed(Runnable r, long delayMillis)
-    {
+    public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
         return sendMessageDelayed(getPostMessage(r), delayMillis);
     }
     
@@ -495,8 +497,8 @@
      *         if the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public final boolean postDelayed(Runnable r, Object token, long delayMillis)
-    {
+    public final boolean postDelayed(
+            @NonNull Runnable r, @Nullable Object token, long delayMillis) {
         return sendMessageDelayed(getPostMessage(r, token), delayMillis);
     }
 
@@ -515,8 +517,7 @@
      *         message queue.  Returns false on failure, usually because the
      *         looper processing the message queue is exiting.
      */
-    public final boolean postAtFrontOfQueue(Runnable r)
-    {
+    public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
         return sendMessageAtFrontOfQueue(getPostMessage(r));
     }
 
@@ -560,7 +561,7 @@
      * If we ever do make it part of the API, we might want to rename it to something
      * less funny like runUnsafe().
      */
-    public final boolean runWithScissors(final Runnable r, long timeout) {
+    public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
         if (r == null) {
             throw new IllegalArgumentException("runnable must not be null");
         }
@@ -580,8 +581,7 @@
     /**
      * Remove any pending posts of Runnable r that are in the message queue.
      */
-    public final void removeCallbacks(Runnable r)
-    {
+    public final void removeCallbacks(@NonNull Runnable r) {
         mQueue.removeMessages(this, r, null);
     }
 
@@ -590,8 +590,7 @@
      * <var>token</var> that are in the message queue.  If <var>token</var> is null,
      * all callbacks will be removed.
      */
-    public final void removeCallbacks(Runnable r, Object token)
-    {
+    public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
         mQueue.removeMessages(this, r, token);
     }
 
@@ -604,8 +603,7 @@
      *         message queue.  Returns false on failure, usually because the
      *         looper processing the message queue is exiting.
      */
-    public final boolean sendMessage(Message msg)
-    {
+    public final boolean sendMessage(@NonNull Message msg) {
         return sendMessageDelayed(msg, 0);
     }
 
@@ -664,8 +662,7 @@
      *         the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public final boolean sendMessageDelayed(Message msg, long delayMillis)
-    {
+    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
         if (delayMillis < 0) {
             delayMillis = 0;
         }
@@ -691,7 +688,7 @@
      *         the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
         MessageQueue queue = mQueue;
         if (queue == null) {
             RuntimeException e = new RuntimeException(
@@ -714,7 +711,7 @@
      *         message queue.  Returns false on failure, usually because the
      *         looper processing the message queue is exiting.
      */
-    public final boolean sendMessageAtFrontOfQueue(Message msg) {
+    public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
         MessageQueue queue = mQueue;
         if (queue == null) {
             RuntimeException e = new RuntimeException(
@@ -734,7 +731,7 @@
      *         looper processing the message queue is exiting.
      * @hide
      */
-    public final boolean executeOrSendMessage(Message msg) {
+    public final boolean executeOrSendMessage(@NonNull Message msg) {
         if (mLooper == Looper.myLooper()) {
             dispatchMessage(msg);
             return true;
@@ -742,7 +739,8 @@
         return sendMessage(msg);
     }
 
-    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
+    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
+            long uptimeMillis) {
         msg.target = this;
         msg.workSourceUid = ThreadLocalWorkSource.getUid();
 
@@ -765,7 +763,7 @@
      * 'object' that are in the message queue.  If <var>object</var> is null,
      * all messages will be removed.
      */
-    public final void removeMessages(int what, Object object) {
+    public final void removeMessages(int what, @Nullable Object object) {
         mQueue.removeMessages(this, what, object);
     }
 
@@ -774,7 +772,7 @@
      * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
      * all callbacks and messages will be removed.
      */
-    public final void removeCallbacksAndMessages(Object token) {
+    public final void removeCallbacksAndMessages(@Nullable Object token) {
         mQueue.removeCallbacksAndMessages(this, token);
     }
 
@@ -798,7 +796,7 @@
      * Check if there are any pending posts of messages with code 'what' and
      * whose obj is 'object' in the message queue.
      */
-    public final boolean hasMessages(int what, Object object) {
+    public final boolean hasMessages(int what, @Nullable Object object) {
         return mQueue.hasMessages(this, what, object);
     }
 
@@ -806,17 +804,18 @@
      * Check if there are any pending posts of messages with callback r in
      * the message queue.
      */
-    public final boolean hasCallbacks(Runnable r) {
+    public final boolean hasCallbacks(@NonNull Runnable r) {
         return mQueue.hasMessages(this, r, null);
     }
 
     // if we can get rid of this method, the handler need not remember its loop
     // we could instead export a getMessageQueue() method... 
+    @NonNull
     public final Looper getLooper() {
         return mLooper;
     }
 
-    public final void dump(Printer pw, String prefix) {
+    public final void dump(@NonNull Printer pw, @NonNull String prefix) {
         pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
         if (mLooper == null) {
             pw.println(prefix + "looper uninitialized");
@@ -828,7 +827,7 @@
     /**
      * @hide
      */
-    public final void dumpMine(Printer pw, String prefix) {
+    public final void dumpMine(@NonNull Printer pw, @NonNull String prefix) {
         pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
         if (mLooper == null) {
             pw.println(prefix + "looper uninitialized");
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index cb794ad..2143a0d 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -471,10 +471,12 @@
      * the most recently modified documents.
      * <p>
      * If this method is overriden by the concrete DocumentsProvider and
-     * QUERY_ARGS_LIMIT is specified with a nonnegative int under queryArgs, the
-     * result will be limited by that number and QUERY_ARG_LIMIT will be
-     * specified under EXTRA_HONORED_ARGS. Otherwise, a default 64 limit will
-     * be used and no QUERY_ARG* will be specified under EXTRA_HONORED_ARGS.
+     * {@link ContentResolver#QUERY_ARG_LIMIT} is specified with a nonnegative
+     * int under queryArgs, the result will be limited by that number and
+     * {@link ContentResolver#QUERY_ARG_LIMIT} will be specified under
+     * {@link ContentResolver#EXTRA_HONORED_ARGS}. Otherwise, a default 64 limit
+     * will be used and no QUERY_ARG* will be specified under
+     * {@link ContentResolver#EXTRA_HONORED_ARGS}.
      * <p>
      * Recent documents do not support change notifications.
      *
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
index 86f99bb..45a8466 100644
--- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -185,7 +185,7 @@
 
     /**
      * For temporary compat reason, remove with b/127532182
-     * @deprecated
+     * @deprecated use {@link #onProcessContextImage(int, Bitmap, Bundle)} instead.
      */
     @Deprecated
     public void processContextImage(
@@ -194,7 +194,8 @@
 
     /**
      * For temporary compat reason, remove with b/127532182
-     * @deprecated
+     * @deprecated use {@link #onSuggestContentSelections(SelectionsRequest,
+     * ContentSuggestionsManager.SelectionsCallback)} instead.
      */
     @Deprecated
     public void suggestContentSelections(@NonNull SelectionsRequest request,
@@ -203,7 +204,8 @@
 
     /**
      * For temporary compat reason, remove with b/127532182
-     * @deprecated
+     * @deprecated use {@link #onClassifyContentSelections(ClassificationsRequest,
+     * ContentSuggestionsManager.ClassificationsCallback)} instead.
      */
     @Deprecated
     public void classifyContentSelections(@NonNull ClassificationsRequest request,
@@ -212,7 +214,7 @@
 
     /**
      * For temporary compat reason, remove with b/127532182
-     * @deprecated
+     * @deprecated use {@link #onNotifyInteraction(String, Bundle)} instead.
      */
     @Deprecated
     public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b99336b..7747a55 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -48,7 +48,7 @@
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
-        DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false");
+        DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
         DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index fd978f5..91928b5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -420,6 +420,10 @@
                 if (isFinishing() || isDestroyed()) {
                     return;
                 }
+                // May be null if there are no apps to perform share/open action.
+                if (mChooserListAdapter == null) {
+                    return;
+                }
                 final List<DisplayResolveInfo> driList =
                         getDisplayResolveInfos(mChooserListAdapter);
                 final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index d6a8934..9d85a03 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -56,7 +56,6 @@
 
     private final TonalPalette mGreyPalette;
     private final ArrayList<TonalPalette> mTonalPalettes;
-    private final ArrayList<ColorRange> mBlacklistedColors;
 
     // Temporary variable to avoid allocations
     private float[] mTmpHSL = new float[3];
@@ -65,7 +64,6 @@
 
         ConfigParser parser = new ConfigParser(context);
         mTonalPalettes = parser.getTonalPalettes();
-        mBlacklistedColors = parser.getBlacklistedColors();
 
         mGreyPalette = mTonalPalettes.get(0);
         mTonalPalettes.remove(0);
@@ -131,7 +129,7 @@
                     Color.blue(colorValue), hsl);
 
             // Stop when we find a color that meets our criteria
-            if (!generatedFromBitmap || !isBlacklisted(hsl)) {
+            if (!generatedFromBitmap) {
                 bestColor = color;
                 break;
             }
@@ -300,22 +298,6 @@
         return getColorPalette(palette.h, palette.s, palette.l);
     }
 
-
-    /**
-     * Checks if a given color exists in the blacklist
-     * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1)
-     * @return true if color should be avoided
-     */
-    private boolean isBlacklisted(float[] hsl) {
-        for (int i = mBlacklistedColors.size() - 1; i >= 0; i--) {
-            ColorRange badRange = mBlacklistedColors.get(i);
-            if (badRange.containsColor(hsl[0], hsl[1], hsl[2])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Offsets all colors by a delta, clamping values that go beyond what's
      * supported on the color space.
@@ -364,11 +346,6 @@
         return minErrorIndex;
     }
 
-    @VisibleForTesting
-    public List<ColorRange> getBlacklistedColors() {
-        return mBlacklistedColors;
-    }
-
     @Nullable
     private TonalPalette findTonalPalette(float h, float s) {
         // Fallback to a grey palette if the color is too desaturated.
@@ -502,11 +479,9 @@
     @VisibleForTesting
     public static class ConfigParser {
         private final ArrayList<TonalPalette> mTonalPalettes;
-        private final ArrayList<ColorRange> mBlacklistedColors;
 
         public ConfigParser(Context context) {
             mTonalPalettes = new ArrayList<>();
-            mBlacklistedColors = new ArrayList<>();
 
             // Load all palettes and the blacklist from an XML.
             try {
@@ -520,8 +495,6 @@
                         String tagName = parser.getName();
                         if (tagName.equals("palettes")) {
                             parsePalettes(parser);
-                        } else if (tagName.equals("blacklist")) {
-                            parseBlacklist(parser);
                         }
                     } else {
                         throw new XmlPullParserException("Invalid XML event " + eventType + " - "
@@ -538,28 +511,6 @@
             return mTonalPalettes;
         }
 
-        public ArrayList<ColorRange> getBlacklistedColors() {
-            return mBlacklistedColors;
-        }
-
-        private void parseBlacklist(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            parser.require(XmlPullParser.START_TAG, null, "blacklist");
-            while (parser.next() != XmlPullParser.END_TAG) {
-                if (parser.getEventType() != XmlPullParser.START_TAG) {
-                    continue;
-                }
-                String name = parser.getName();
-                // Starts by looking for the entry tag
-                if (name.equals("range")) {
-                    mBlacklistedColors.add(readRange(parser));
-                    parser.next();
-                } else {
-                    throw new XmlPullParserException("Invalid tag: " + name, parser, null);
-                }
-            }
-        }
-
         private ColorRange readRange(XmlPullParser parser)
                 throws XmlPullParserException, IOException {
             parser.require(XmlPullParser.START_TAG, null, "range");
diff --git a/core/res/res/xml/color_extraction.xml b/core/res/res/xml/color_extraction.xml
index 93ab0ff..c3ebe4e 100644
--- a/core/res/res/xml/color_extraction.xml
+++ b/core/res/res/xml/color_extraction.xml
@@ -246,109 +246,4 @@
                 0.6549019607843137,0.7549019607843137,0.8509803921568627,
                 0.9411764705882353"/>
     </palettes>
-    <blacklist>
-        <!-- Red -->
-        <range h="0, 20"
-               s="0.7, 1"
-               l="0.21, 0.79"/>
-        <range h="0, 20"
-               s="0.3, 0.7"
-               l="0.355, 0.653"/>
-        <!-- Red Orange -->
-        <range h="20, 40"
-               s="0.7, 1"
-               l="0.2, 0.643"/>
-        <range h="20, 40"
-               s="0.3, 0.7"
-               l="0.414, 0.561"/>
-        <range h="20, 40"
-               s="0, 0.3"
-               l="0.343, 0.584"/>
-        <!-- Orange -->
-        <range h="40, 60"
-               s="0.7, 1"
-               l="0.173, 0.38"/>
-        <range h="40, 60"
-               s="0.3, 0.7"
-               l="0.233, 0.427"/>
-        <range h="40, 60"
-               s="0, 0.3"
-               l="0.231, 0.48"/>
-        <!-- Yellow 60 -->
-        <range h="60, 80"
-               s="0.7, 1"
-               l="0.15, 0.40"/>
-        <range h="60, 80"
-               s="0.3, 0.7"
-               l="0.15, 0.42"/>
-        <range h="60, 80"
-               s="0, 0.3"
-               l="0.35, 0.57"/>
-        <!-- Yellow Green 80 -->
-        <range h="80, 100"
-               s="0.7, 1"
-               l="0.36, 0.65"/>
-        <range h="80, 100"
-               s="0.3, 0.7"
-               l="0.48, 0.57"/>
-        <!-- Yellow green 100 -->
-        <range h="100, 120"
-               s="0.7, 1"
-               l="0.388, 0.67"/>
-        <range h="100, 120"
-               s="0.3, 0.7"
-               l="0.424, 0.58"/>
-        <!-- Green -->
-        <range h="120, 140"
-               s="0.7, 1"
-               l="0.37, 0.65"/>
-        <range h="120, 140"
-               s="0.3, 0.7"
-               l="0.435, 0.58"/>
-        <!-- Green Blue 140 -->
-        <range h="140, 160"
-               s="0.7, 1"
-               l="0.43, 0.641"/>
-        <!-- Seaoam -->
-        <range h="160, 180"
-               s="0.7, 1"
-               l="0.496, 0.567"/>
-        <!-- Cyan -->
-        <range h="180, 200"
-               s="0.7, 1"
-               l="0.52, 0.729"/>
-        <!-- Blue -->
-        <range h="220, 240"
-               s="0.7, 1"
-               l="0.396, 0.571"/>
-        <range h="220, 240"
-               s="0.3, 0.7"
-               l="0.425, 0.551"/>
-        <!-- Blue Purple 240 -->
-        <range h="240, 260"
-               s="0.7, 1"
-               l="0.418, 0.639"/>
-        <range h="220, 240"
-               s="0.3, 0.7"
-               l="0.441, 0.576"/>
-        <!-- Blue Purple 260 -->
-        <range h="260, 280"
-               s="0.3, 1"
-               l="0.461, 0.553"/>
-        <!-- Fuchsia -->
-        <range h="300, 320"
-               s="0.7, 1"
-               l="0.484, 0.588"/>
-        <range h="300, 320"
-               s="0.3, 0.7"
-               l="0.48, 0.592"/>
-        <!-- Pink -->
-        <range h="320, 340"
-               s="0.7, 1"
-               l="0.466, 0.629"/>
-        <!-- Soft red -->
-        <range h="340, 360"
-               s="0.7, 1"
-               l="0.437, 0.596"/>
-    </blacklist>
-</colorextraction>
\ No newline at end of file
+</colorextraction>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9d6fc9ed..6df6c73 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -135,6 +135,7 @@
     <uses-permission android:name="android.permission.MANAGE_BIOMETRIC" />
     <uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
+    <uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
 
     <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
     <uses-permission android:name="android.permission.SET_WALLPAPER"/>
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 4d8cf96..59ee267 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -76,8 +76,10 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX, true);
-        final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY, false);
+        final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX * 2, true)
+                - mBurnInPreventionOffsetX;
+        final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
+                - mBurnInPreventionOffsetY;
 
         // Put digital clock in two left corner of the screen.
         if (mDigitalClock != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index c013df3..ace086f 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -20,6 +20,7 @@
 
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -203,26 +204,37 @@
     }
 
     /**
+     * Does the app-op item refer to a user sensitive permission. Only user sensitive permission
+     * should be shown to the user by default.
+     *
+     * @param item The item
+     *
+     * @return {@code true} iff the app-op item is user sensitive
+     */
+    private boolean isUserSensitive(AppOpItem item) {
+        String permission = AppOpsManager.opToPermission(item.getCode());
+        if (permission == null) {
+            return false;
+        }
+        int permFlags = mContext.getPackageManager().getPermissionFlags(permission,
+                item.getPackageName(), UserHandle.getUserHandleForUid(item.getUid()));
+        return (permFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
+    }
+
+    /**
      * Returns a copy of the list containing all the active AppOps that the controller tracks.
      *
      * @return List of active AppOps information
      */
     public List<AppOpItem> getActiveAppOps() {
-        ArrayList<AppOpItem> active;
-        synchronized (mActiveItems) {
-            active = new ArrayList<>(mActiveItems);
-        }
-        synchronized (mNotedItems) {
-            active.addAll(mNotedItems);
-        }
-        return active;
+        return getActiveAppOpsForUser(UserHandle.USER_ALL);
     }
 
     /**
      * Returns a copy of the list containing all the active AppOps that the controller tracks, for
      * a given user id.
      *
-     * @param userId User id to track
+     * @param userId User id to track, can be {@link UserHandle#USER_ALL}
      *
      * @return List of active AppOps information for that user id
      */
@@ -232,7 +244,8 @@
             final int numActiveItems = mActiveItems.size();
             for (int i = 0; i < numActiveItems; i++) {
                 AppOpItem item = mActiveItems.get(i);
-                if (UserHandle.getUserId(item.getUid()) == userId) {
+                if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId)
+                        && isUserSensitive(item)) {
                     list.add(item);
                 }
             }
@@ -241,7 +254,8 @@
             final int numNotedItems = mNotedItems.size();
             for (int i = 0; i < numNotedItems; i++) {
                 AppOpItem item = mNotedItems.get(i);
-                if (UserHandle.getUserId(item.getUid()) == userId) {
+                if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId)
+                        && isUserSensitive(item)) {
                     list.add(item);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 51b2098..eb85589 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -23,6 +23,8 @@
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
@@ -42,6 +44,7 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.MainThread;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -59,6 +62,8 @@
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 
+import java.lang.annotation.Retention;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -70,10 +75,22 @@
  */
 @Singleton
 public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
-    private static final int MAX_BUBBLES = 5; // TODO: actually enforce this
 
     private static final String TAG = "BubbleController";
 
+    private static final int MAX_BUBBLES = 5; // TODO: actually enforce this
+
+    @Retention(SOURCE)
+    @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
+            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
+    @interface DismissReason {}
+    static final int DISMISS_USER_GESTURE = 1;
+    static final int DISMISS_AGED = 2;
+    static final int DISMISS_TASK_FINISHED = 3;
+    static final int DISMISS_BLOCKED = 4;
+    static final int DISMISS_NOTIF_CANCEL = 5;
+    static final int DISMISS_ACCESSIBILITY_ACTION = 6;
+
     // Enables some subset of notifs to automatically become bubbles
     private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
 
@@ -248,11 +265,11 @@
     /**
      * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
      */
-    void dismissStack() {
+    void dismissStack(@DismissReason int reason) {
         if (mStackView == null) {
             return;
         }
-        mStackView.stackDismissed();
+        mStackView.stackDismissed(reason);
 
         updateVisibility();
         mNotificationEntryManager.updateNotifications();
@@ -304,9 +321,9 @@
      * Must be called from the main thread.
      */
     @MainThread
-    void removeBubble(String key) {
+    void removeBubble(String key, int reason) {
         if (mStackView != null) {
-            mStackView.removeBubble(key);
+            mStackView.removeBubble(key, reason);
         }
         mNotificationEntryManager.updateNotifications();
         updateVisibility();
@@ -320,7 +337,7 @@
             boolean samePackage = entry.notification.getPackageName().equals(
                     e.notification.getPackageName());
             if (samePackage) {
-                removeBubble(entry.key);
+                removeBubble(entry.key, DISMISS_BLOCKED);
             }
         }
     }
@@ -377,7 +394,7 @@
             }
             if (!removedByUser) {
                 // This was a cancel so we should remove the bubble
-                removeBubble(entry.key);
+                removeBubble(entry.key, DISMISS_NOTIF_CANCEL);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 25ee87a..856b9d6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -135,7 +135,8 @@
         public void onTaskRemovalStarted(int taskId) {
             if (mEntry != null) {
                 // Must post because this is called from a binder thread.
-                post(() -> mBubbleController.removeBubble(mEntry.key));
+                post(() -> mBubbleController.removeBubble(mEntry.key,
+                        BubbleController.DISMISS_TASK_FINISHED));
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 84efb9a..888e3fe 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,6 +19,8 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Outline;
@@ -49,6 +51,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController.DismissReason;
 import com.android.systemui.bubbles.animation.ExpandedAnimationController;
 import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
 import com.android.systemui.bubbles.animation.StackAnimationController;
@@ -62,6 +65,7 @@
  */
 public class BubbleStackView extends FrameLayout {
     private static final String TAG = "BubbleStackView";
+    private static final boolean DEBUG = false;
 
     private Point mDisplaySize;
 
@@ -232,7 +236,7 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_DISMISS:
-                stackDismissed();
+                stackDismissed(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
                 return true;
             case AccessibilityNodeInfo.ACTION_COLLAPSE:
                 collapseStack();
@@ -356,18 +360,12 @@
     /**
      * Remove a bubble from the stack.
      */
-    public void removeBubble(String key) {
+    public void removeBubble(String key, int reason) {
         Bubble b = mBubbleData.removeBubble(key);
         if (b == null) {
             return;
         }
-        b.entry.setBubbleDismissed(true);
-
-        // Remove it from the views
-        int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
-        b.expandedView.cleanUpExpandedState();
-        mBubbleContainer.removeView(b.iconView);
-
+        int removedIndex = dismissBubble(b, reason);
         int bubbleCount = mBubbleContainer.getChildCount();
         if (bubbleCount == 0) {
             // If no bubbles remain, collapse the entire stack.
@@ -385,26 +383,63 @@
                 mExpandedBubble = null;
             }
         }
+        // TODO: consider logging reason code
         logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
     }
 
     /**
      * Dismiss the stack of bubbles.
      */
-    public void stackDismissed() {
+    public void stackDismissed(int reason) {
         for (Bubble bubble : mBubbleData.getBubbles()) {
-            bubble.entry.setBubbleDismissed(true);
-            bubble.expandedView.cleanUpExpandedState();
+            dismissBubble(bubble, reason);
         }
         mBubbleData.clear();
         collapseStack();
         mBubbleContainer.removeAllViews();
         mExpandedViewContainer.removeAllViews();
+        // TODO: consider logging reason code
         logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
                 StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
     }
 
     /**
+     * Marks the notification entry as dismissed, cleans up Bubble icon and expanded view UI
+     * elements and calls deleteIntent if necessary.
+     *
+     * <p>Note: This does not remove the Bubble from BubbleData.
+     *
+     * @param bubble the Bubble being dismissed
+     * @param reason code for the reason the dismiss was triggered
+     * @see BubbleController.DismissReason
+     */
+    private int dismissBubble(Bubble bubble, @DismissReason int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason);
+        }
+        bubble.entry.setBubbleDismissed(true);
+        bubble.expandedView.cleanUpExpandedState();
+
+        // Remove it from the views
+        int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView);
+        mBubbleContainer.removeViewAt(removedIndex);
+
+        if (reason == BubbleController.DISMISS_USER_GESTURE) {
+            Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata();
+            PendingIntent deleteIntent = bubbleMetadata.getDeleteIntent();
+            if (deleteIntent != null) {
+                try {
+                    deleteIntent.send();
+                } catch (PendingIntent.CanceledException e) {
+                    Log.w(TAG, "Failed to send delete intent for bubble with key: "
+                            + (bubble.entry != null ? bubble.entry.key : " null entry"));
+                }
+            }
+        }
+        return removedIndex;
+    }
+
+    /**
      * Updates a bubble in the stack.
      *
      * @param entry the entry to update in the stack.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index c8eebac..a7170d0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -140,7 +140,7 @@
             case MotionEvent.ACTION_UP:
                 trackMovement(event);
                 if (mInDismissTarget && isStack) {
-                    mController.dismissStack();
+                    mController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
                 } else if (mMovedEnough) {
                     mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
                     final float velX = mVelocityTracker.getXVelocity();
@@ -152,7 +152,8 @@
                         mStack.onBubbleDragFinish(
                                 mTouchedView, viewX, viewY, velX, velY, /* dismissed */ dismissed);
                         if (dismissed) {
-                            mController.removeBubble(((BubbleView) mTouchedView).getKey());
+                            mController.removeBubble(((BubbleView) mTouchedView).getKey(),
+                                    BubbleController.DISMISS_USER_GESTURE);
                         }
                     }
                 } else if (mTouchedView == mStack.getExpandedBubbleView()) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 3273253..9b44066 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -89,6 +89,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
@@ -1533,7 +1534,7 @@
             View panelView = initializePanel();
             if (panelView == null) {
                 mBackgroundDrawable = new GradientDrawable(context);
-                mScrimAlpha = 0.7f;
+                mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
             } else {
                 mBackgroundDrawable = context.getDrawable(
                         com.android.systemui.R.drawable.global_action_panel_scrim);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 73ee0bd..b9afea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -22,11 +22,14 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -47,12 +50,15 @@
 @TestableLooper.RunWithLooper
 public class AppOpsControllerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
-    private static final int TEST_UID = 0;
-    private static final int TEST_UID_OTHER = 500000;
+    private static final int TEST_UID = UserHandle.getUid(0, 0);
+    private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0);
+    private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0);
 
     @Mock
     private AppOpsManager mAppOpsManager;
     @Mock
+    private PackageManager mPackageManager;
+    @Mock
     private AppOpsController.Callback mCallback;
     @Mock
     private AppOpsControllerImpl.H mMockHandler;
@@ -65,6 +71,18 @@
 
         getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager);
 
+        // All permissions of TEST_UID and TEST_UID_OTHER are user sensitive. None of
+        // TEST_UID_NON_USER_SENSITIVE are user sensitive.
+        getContext().setMockPackageManager(mPackageManager);
+        when(mPackageManager.getPermissionFlags(anyString(), anyString(),
+                eq(UserHandle.getUserHandleForUid(TEST_UID)))).thenReturn(
+                PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
+        when(mPackageManager.getPermissionFlags(anyString(), anyString(),
+                eq(UserHandle.getUserHandleForUid(TEST_UID_OTHER)))).thenReturn(
+                PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
+        when(mPackageManager.getPermissionFlags(anyString(), anyString(),
+                eq(UserHandle.getUserHandleForUid(TEST_UID_NON_USER_SENSITIVE)))).thenReturn(0);
+
         mController = new AppOpsControllerImpl(mContext, Dependency.get(Dependency.BG_LOOPER));
     }
 
@@ -157,6 +175,14 @@
     }
 
     @Test
+    public void nonUserSensitiveOpsAreIgnored() {
+        mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
+                TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true);
+        assertEquals(0, mController.getActiveAppOpsForUser(
+                UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
+    }
+
+    @Test
     public void opNotedScheduledForRemoval() {
         mController.setBGHandler(mMockHandler);
         mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 0fd7834..42c221a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -20,10 +20,13 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.IActivityManager;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -83,6 +86,9 @@
     @Mock
     private BubbleController.BubbleExpandListener mBubbleExpandListener;
 
+    @Mock
+    private PendingIntent mDeleteIntent;
+
     private BubbleData mBubbleData;
 
     @Before
@@ -98,9 +104,9 @@
 
         // Need notifications for bubbles
         mNotificationTestHelper = new NotificationTestHelper(mContext);
-        mRow = mNotificationTestHelper.createBubble();
-        mRow2 = mNotificationTestHelper.createBubble();
-        mNoChannelRow = mNotificationTestHelper.createBubble();
+        mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
+        mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
+        mNoChannelRow = mNotificationTestHelper.createBubble(mDeleteIntent);
 
         // Return non-null notification data from the NEM
         when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
@@ -141,11 +147,10 @@
 
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
-        mBubbleController.removeBubble(mRow.getEntry().key);
+        mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
         assertFalse(mStatusBarWindowController.getBubblesShowing());
         assertTrue(mRow.getEntry().isBubbleDismissed());
         verify(mNotificationEntryManager).updateNotifications();
-
         verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
     }
 
@@ -155,7 +160,7 @@
         mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
         assertTrue(mBubbleController.hasBubbles());
 
-        mBubbleController.dismissStack();
+        mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
         assertFalse(mStatusBarWindowController.getBubblesShowing());
         verify(mNotificationEntryManager).updateNotifications();
         assertTrue(mRow.getEntry().isBubbleDismissed());
@@ -271,7 +276,8 @@
         assertFalse(mRow2.getEntry().showInShadeWhenBubble());
 
         // Dismiss currently expanded
-        mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
+        mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
+                BubbleController.DISMISS_USER_GESTURE);
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
 
         // Make sure next bubble is selected
@@ -279,7 +285,8 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
 
         // Dismiss that one
-        mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
+        mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
+                BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
@@ -299,6 +306,28 @@
         assertTrue(mRow.getEntry().showInShadeWhenBubble());
     }
 
+    @Test
+    public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
+        mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_AGED);
+        verify(mDeleteIntent, never()).send();
+    }
+
+    @Test
+    public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
+        mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
+        verify(mDeleteIntent, times(1)).send();
+    }
+
+    @Test
+    public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
+        mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
+        mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
+        verify(mDeleteIntent, times(2)).send();
+    }
+
     static class TestableBubbleController extends BubbleController {
 
         TestableBubbleController(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index cef78db..de15505 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -23,6 +23,7 @@
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.Notification;
+import android.app.Notification.BubbleMetadata;
 import android.app.NotificationChannel;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -152,8 +153,18 @@
      * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
      */
     public ExpandableNotificationRow createBubble() throws Exception {
+        return createBubble(null);
+    }
+
+    /**
+     * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
+     *
+     * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
+     */
+    public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent)
+            throws Exception {
         Notification n = createNotification(false /* isGroupSummary */,
-                null /* groupKey */, true /* isBubble */);
+                null /* groupKey */, true /* isBubble */, deleteIntent);
         return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
     }
 
@@ -196,7 +207,8 @@
      * @return a notification that is in the group specified or standalone if unspecified
      */
     private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) {
-        return createNotification(isGroupSummary, groupKey, false /* isBubble */);
+        return createNotification(isGroupSummary, groupKey, false /* isBubble */,
+                null /* bubbleDeleteIntent */);
     }
 
     /**
@@ -208,7 +220,8 @@
      * @return a notification that is in the group specified or standalone if unspecified
      */
     private Notification createNotification(boolean isGroupSummary,
-            @Nullable String groupKey, boolean isBubble) {
+            @Nullable String groupKey, boolean isBubble,
+            @Nullable PendingIntent bubbleDeleteIntent) {
         Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
                 R.drawable.ic_person)
                 .setCustomContentView(new RemoteViews(mContext.getPackageName(),
@@ -227,7 +240,8 @@
             notificationBuilder.setGroup(groupKey);
         }
         if (isBubble) {
-            notificationBuilder.setBubbleMetadata(makeBubbleMetadata());
+            BubbleMetadata metadata = makeBubbleMetadata(bubbleDeleteIntent);
+            notificationBuilder.setBubbleMetadata(metadata);
         }
         return notificationBuilder.build();
     }
@@ -291,11 +305,13 @@
         return row;
     }
 
-    private Notification.BubbleMetadata makeBubbleMetadata() {
+    private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent) {
         Intent target = new Intent(mContext, BubblesTestActivity.class);
         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
-        return new Notification.BubbleMetadata.Builder()
+
+        return new BubbleMetadata.Builder()
                 .setIntent(bubbleIntent)
+                .setDeleteIntent(deleteIntent)
                 .setTitle("bubble title")
                 .setIcon(Icon.createWithResource(mContext, 1))
                 .setDesiredHeight(314)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8edc5b4..8ad0959 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2938,7 +2938,7 @@
     }
 
     /**
-     * Enabled or disable a subscription. This is currently used in the settings page.
+     * Enables or disables a subscription. This is currently used in the settings page.
      *
      * <p>
      * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index d92cfce..300182d 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -27,7 +27,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.graphics.ColorUtils;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -96,7 +95,6 @@
         Tonal.ConfigParser config = new Tonal.ConfigParser(InstrumentationRegistry.getContext());
         // 1 to avoid regression where only first item would be parsed.
         assertTrue("Tonal palettes are empty", config.getTonalPalettes().size() > 1);
-        assertTrue("Blacklisted colors are empty", config.getBlacklistedColors().size() > 1);
     }
 
     @Test
@@ -113,41 +111,4 @@
             assertTrue("L should be <= to 1.", palette.l[1] <= 1);
         }
     }
-
-    @Test
-    public void tonal_blacklistTest() {
-        // Make sure that palette generation will fail.
-        final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
-
-        // Creating a WallpaperColors object that contains *only* blacklisted colors.
-        final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
-        final int blacklistedColor = ColorUtils.HSLToColor(hsl);
-        WallpaperColors colorsFromBitmap = new WallpaperColors(Color.valueOf(blacklistedColor),
-                null, null, WallpaperColors.HINT_FROM_BITMAP);
-
-        // Make sure that palette generation will fail
-        final GradientColors normal = new GradientColors();
-        tonal.extractInto(colorsFromBitmap, normal, new GradientColors(),
-                new GradientColors());
-        assertTrue("Cannot generate a tonal palette from blacklisted colors.",
-                normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
-    }
-
-    @Test
-    public void tonal_ignoreBlacklistTest() {
-        final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
-
-        // Creating a WallpaperColors object that contains *only* blacklisted colors.
-        final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
-        final int blacklistedColor = ColorUtils.HSLToColor(hsl);
-        WallpaperColors colors = new WallpaperColors(Color.valueOf(blacklistedColor),
-                null, null);
-
-        // Blacklist should be ignored when HINT_FROM_BITMAP isn't present.
-        final GradientColors normal = new GradientColors();
-        tonal.extractInto(colors, normal, new GradientColors(),
-                new GradientColors());
-        assertTrue("Blacklist should never be used on WallpaperColors generated using "
-                + "default constructor.", normal.getMainColor() == blacklistedColor);
-    }
 }