Merge "Do not blur shade while fading away" into rvc-dev
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index b3c82bc..073fddf 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -850,7 +850,7 @@
     private final InputReadingDataSource mDataSource;
     private final DataReaderAdapter mScratchDataReaderAdapter;
     private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
-    private String mExtractorName;
+    private String mParserName;
     private Extractor mExtractor;
     private ExtractorInput mExtractorInput;
     private long mPendingSeekPosition;
@@ -924,7 +924,7 @@
     @NonNull
     @ParserName
     public String getParserName() {
-        return mExtractorName;
+        return mParserName;
     }
 
     /**
@@ -958,15 +958,15 @@
 
         // TODO: Apply parameters when creating extractor instances.
         if (mExtractor == null) {
-            if (!mExtractorName.equals(PARSER_NAME_UNKNOWN)) {
-                mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+            if (!mParserName.equals(PARSER_NAME_UNKNOWN)) {
+                mExtractor = createExtractor(mParserName);
                 mExtractor.init(new ExtractorOutputAdapter());
             } else {
                 for (String parserName : mParserNamesPool) {
                     Extractor extractor = createExtractor(parserName);
                     try {
                         if (extractor.sniff(mExtractorInput)) {
-                            mExtractorName = parserName;
+                            mParserName = parserName;
                             mExtractor = extractor;
                             mExtractor.init(new ExtractorOutputAdapter());
                             break;
@@ -1044,7 +1044,7 @@
         mParserParameters = new HashMap<>();
         mOutputConsumer = outputConsumer;
         mParserNamesPool = parserNamesPool;
-        mExtractorName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0];
+        mParserName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0];
         mPositionHolder = new PositionHolder();
         mDataSource = new InputReadingDataSource();
         removePendingSeek();
@@ -1090,7 +1090,7 @@
                         getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS)
                                 ? Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
                                 : 0;
-                return new Mp4Extractor();
+                return new Mp4Extractor(flags);
             case PARSER_NAME_MP3:
                 flags |=
                         getBooleanParameter(PARAMETER_MP3_DISABLE_ID3)
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9ca2db9..d36d583 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3158,6 +3158,23 @@
             "android.content.pm.extra.VERIFICATION_LONG_VERSION_CODE";
 
     /**
+     * Extra field name for the Merkle tree root hash of a package.
+     * <p>Passed to a package verifier both prior to verification and as a result
+     * of verification.
+     * <p>The value of the extra is a specially formatted list:
+     * {@code filename1:HASH_1;filename2:HASH_2;...;filenameN:HASH_N}
+     * <p>The extra must include an entry for every APK within an installation. If
+     * a hash is not physically present, a hash value of {@code 0} will be used.
+     * <p>The root hash is generated using SHA-256, no salt with a 4096 byte block
+     * size. See the description of the
+     * <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#merkle-tree">fs-verity merkle-tree</a>
+     * for more details.
+     * @hide
+     */
+    public static final String EXTRA_VERIFICATION_ROOT_HASH =
+            "android.content.pm.extra.EXTRA_VERIFICATION_ROOT_HASH";
+
+    /**
      * Extra field name for the ID of a intent filter pending verification.
      * Passed to an intent filter verifier and is used to call back to
      * {@link #verifyIntentFilter}
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 5cc73ca..d35ce5b 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -16,6 +16,8 @@
 
 package android.os.incremental;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.ParcelFileDescriptor;
 
 import java.io.ByteArrayInputStream;
@@ -45,8 +47,8 @@
     public static class HashingInfo {
         public final int hashAlgorithm; // only 1 == SHA256 supported
         public final byte log2BlockSize; // only 12 (block size 4096) supported now
-        public final byte[] salt; // used exactly as in fs-verity, 32 bytes max
-        public final byte[] rawRootHash; // salted digest of the first Merkle tree page
+        @Nullable public final byte[] salt; // used exactly as in fs-verity, 32 bytes max
+        @Nullable public final byte[] rawRootHash; // salted digest of the first Merkle tree page
 
         HashingInfo(int hashAlgorithm, byte log2BlockSize, byte[] salt, byte[] rawRootHash) {
             this.hashAlgorithm = hashAlgorithm;
@@ -58,7 +60,8 @@
         /**
          * Constructs HashingInfo from byte array.
          */
-        public static HashingInfo fromByteArray(byte[] bytes) throws IOException {
+        @NonNull
+        public static HashingInfo fromByteArray(@NonNull byte[] bytes) throws IOException {
             ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
             final int hashAlgorithm = buffer.getInt();
             final byte log2BlockSize = buffer.get();
@@ -106,8 +109,18 @@
     }
 
     public final int version; // Always 2 for now.
-    public final byte[] hashingInfo;
-    public final byte[] signingInfo; // Passed as-is to the kernel. Can be retrieved later.
+    /**
+     * Raw byte array containing the IncFS hashing data.
+     * @see HashingInfo#fromByteArray(byte[])
+     */
+    @Nullable public final byte[] hashingInfo;
+
+    /**
+     * Raw byte array containing the V4 signature data.
+     * <p>Passed as-is to the kernel. Can be retrieved later.
+     * @see SigningInfo#fromByteArray(byte[])
+     */
+    @Nullable public final byte[] signingInfo;
 
     /**
      * Construct a V4Signature from .idsig file.
@@ -121,7 +134,8 @@
     /**
      * Construct a V4Signature from a byte array.
      */
-    public static V4Signature readFrom(byte[] bytes) throws IOException {
+    @NonNull
+    public static V4Signature readFrom(@NonNull byte[] bytes) throws IOException {
         try (InputStream stream = new ByteArrayInputStream(bytes)) {
             return readFrom(stream);
         }
@@ -169,7 +183,7 @@
         return this.version == SUPPORTED_VERSION;
     }
 
-    private V4Signature(int version, byte[] hashingInfo, byte[] signingInfo) {
+    private V4Signature(int version, @Nullable byte[] hashingInfo, @Nullable byte[] signingInfo) {
         this.version = version;
         this.hashingInfo = hashingInfo;
         this.signingInfo = signingInfo;
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3f07873..337027e 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -182,7 +182,6 @@
     private Window mWindow;
     private Activity mActivity;
     private boolean mInteractive;
-    private boolean mLowProfile = true;
     private boolean mFullscreen;
     private boolean mScreenBright = true;
     private boolean mStarted;
@@ -530,32 +529,6 @@
     }
 
     /**
-     * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
-     *
-     * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
-     * @hide There is no reason to have this -- dreams can set this flag
-     * on their own content view, and from there can actually do the
-     * correct interactions with it (seeing when it is cleared etc).
-     */
-    public void setLowProfile(boolean lowProfile) {
-        if (mLowProfile != lowProfile) {
-            mLowProfile = lowProfile;
-            int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
-            applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
-        }
-    }
-
-    /**
-     * Returns whether or not this dream is in low profile mode. Defaults to true.
-     *
-     * @see #setLowProfile(boolean)
-     * @hide
-     */
-    public boolean isLowProfile() {
-        return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
-    }
-
-    /**
      * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
      * on the dream's window.
      *
@@ -1094,10 +1067,6 @@
         // along well. Dreams usually don't need such bars anyways, so disable them by default.
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
 
-        applySystemUiVisibilityFlags(
-                (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
-                View.SYSTEM_UI_FLAG_LOW_PROFILE);
-
         mWindow.getDecorView().addOnAttachStateChangeListener(
                 new View.OnAttachStateChangeListener() {
                     @Override
@@ -1126,18 +1095,6 @@
         }
     }
 
-    private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) {
-        View v = mWindow == null ? null : mWindow.getDecorView();
-        return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0;
-    }
-
-    private void applySystemUiVisibilityFlags(int flags, int mask) {
-        View v = mWindow == null ? null : mWindow.getDecorView();
-        if (v != null) {
-            v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask));
-        }
-    }
-
     private int applyFlags(int oldFlags, int flags, int mask) {
         return (oldFlags&~mask) | (flags&mask);
     }
@@ -1163,7 +1120,6 @@
         pw.println("  window: " + mWindow);
         pw.print("  flags:");
         if (isInteractive()) pw.print(" interactive");
-        if (isLowProfile()) pw.print(" lowprofile");
         if (isFullscreen()) pw.print(" fullscreen");
         if (isScreenBright()) pw.print(" bright");
         if (isWindowless()) pw.print(" windowless");
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 362b94b..3b5a6d5 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -413,6 +413,10 @@
      * {@link #ACTION_VOICE_SEARCH_HANDS_FREE}, {@link #ACTION_WEB_SEARCH} to indicate whether to
      * only use an offline speech recognition engine. The default is false, meaning that either
      * network or offline recognition engines may be used.
+     *
+     * <p>Depending on the recognizer implementation, these values may have
+     * no effect.</p>
+     *
      */
     public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1086774..76ed37c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -228,6 +228,7 @@
      */
     public long mNativeObject;
     private long mNativeHandle;
+    private Throwable mReleaseStack = null;
 
     // TODO: Move this to native.
     private final Object mSizeLock = new Object();
@@ -426,11 +427,18 @@
         if (mNativeObject != 0) {
             release();
         }
-      	if (nativeObject != 0) {
+        if (nativeObject != 0) {
             mCloseGuard.open("release");
         }
         mNativeObject = nativeObject;
         mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
+        if (mNativeObject == 0) {
+            if (Build.IS_DEBUGGABLE) {
+                mReleaseStack = new Throwable("assigned zero nativeObject here");
+            }
+        } else {
+            mReleaseStack = null;
+        }
     }
 
     /**
@@ -989,11 +997,22 @@
             nativeRelease(mNativeObject);
             mNativeObject = 0;
             mNativeHandle = 0;
+            if (Build.IS_DEBUGGABLE) {
+                mReleaseStack = new Throwable("released here");
+            }
             mCloseGuard.close();
         }
     }
 
     /**
+     * Returns the call stack that assigned mNativeObject to zero.
+     * @hide
+     */
+    public Throwable getReleaseStack() {
+        return mReleaseStack;
+    }
+
+    /**
      * Disconnect any client still connected to the surface.
      * @hide
      */
@@ -1004,8 +1023,11 @@
     }
 
     private void checkNotReleased() {
-        if (mNativeObject == 0) throw new NullPointerException(
-                "mNativeObject is null. Have you called release() already?");
+        if (mNativeObject == 0) {
+            Log.wtf(TAG, "Invalid " + this + " caused by:", mReleaseStack);
+            throw new NullPointerException(
+                "mNativeObject of " + this + " is null. Have you called release() already?");
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 350ce29..79d2edd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -266,6 +266,10 @@
 
         mMagnetizedPip = mMotionHelper.getMagnetizedPip();
         mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
+
+        // Set the magnetic field radius equal to twice the size of the target.
+        mMagneticTarget.setMagneticFieldRadiusPx(targetSize * 2);
+
         mMagnetizedPip.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener);
         mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
             @Override
@@ -504,9 +508,6 @@
             mTargetView.setTranslationY(mTargetViewContainer.getHeight());
             mTargetViewContainer.setVisibility(View.VISIBLE);
 
-            // Set the magnetic field radius to half of PIP's width.
-            mMagneticTarget.setMagneticFieldRadiusPx(mMotionHelper.getBounds().width());
-
             // Cancel in case we were in the middle of animating it out.
             mMagneticTargetAnimator.cancel();
             mMagneticTargetAnimator
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index f27bdbf..e905e67 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -27,6 +27,7 @@
 import android.view.MotionEvent
 import android.view.VelocityTracker
 import android.view.View
+import android.view.ViewConfiguration
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringForce
@@ -146,6 +147,10 @@
     private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
     private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
 
+    private var touchDown = PointF()
+    private var touchSlop = 0
+    private var movedBeyondSlop = false
+
     /** Whether touch events are presently occurring within the magnetic field area of a target. */
     val objectStuckToTarget: Boolean
         get() = targetObjectIsStuckTo != null
@@ -324,15 +329,32 @@
         // When a gesture begins, recalculate target views' positions on the screen in case they
         // have changed. Also, clear state.
         if (ev.action == MotionEvent.ACTION_DOWN) {
-            updateTargetViewLocations()
+            updateTargetViews()
 
-            // Clear the velocity tracker and assume we're not stuck to a target yet.
+            // Clear the velocity tracker and stuck target.
             velocityTracker.clear()
             targetObjectIsStuckTo = null
+
+            // Set the touch down coordinates and reset movedBeyondSlop.
+            touchDown.set(ev.rawX, ev.rawY)
+            movedBeyondSlop = false
         }
 
+        // Always pass events to the VelocityTracker.
         addMovement(ev)
 
+        // If we haven't yet moved beyond the slop distance, check if we have.
+        if (!movedBeyondSlop) {
+            val dragDistance = hypot(ev.rawX - touchDown.x, ev.rawY - touchDown.y)
+            if (dragDistance > touchSlop) {
+                // If we're beyond the slop distance, save that and continue.
+                movedBeyondSlop = true
+            } else {
+                // Otherwise, don't do anything yet.
+                return false
+            }
+        }
+
         val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
             val distanceFromTargetCenter = hypot(
                     ev.rawX - target.centerOnScreen.x,
@@ -559,8 +581,14 @@
     }
 
     /** Updates the locations on screen of all of the [associatedTargets]. */
-    internal fun updateTargetViewLocations() {
+    internal fun updateTargetViews() {
         associatedTargets.forEach { it.updateLocationOnScreen() }
+
+        // Update the touch slop, since the configuration may have changed.
+        if (associatedTargets.size > 0) {
+            touchSlop =
+                    ViewConfiguration.get(associatedTargets[0].targetView.context).scaledTouchSlop
+        }
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
index f6b7b74..251ca9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -186,8 +186,8 @@
 
     @Test
     fun testMotionEventConsumption_downInMagneticField() {
-        // We should consume DOWN events if they occur in the field.
-        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+        // We should not consume DOWN events even if they occur in the field.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
                 x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN)))
     }
 
@@ -342,10 +342,14 @@
         // Trigger the magnet animation, and block the test until it ends.
         PhysicsAnimatorTestUtils.setAllAnimationsBlock(true)
         magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
-                x = targetCenterX,
-                y = targetCenterY,
+                x = targetCenterX - 250,
+                y = targetCenterY - 250,
                 action = MotionEvent.ACTION_DOWN))
 
+        magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX,
+                y = targetCenterY))
+
         // The object's (top-left) position should now position it centered over the target.
         assertEquals(targetCenterX - objectSize / 2, objectX)
         assertEquals(targetCenterY - objectSize / 2, objectY)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8ed5846..8eb41ad 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1992,7 +1992,8 @@
                 mPackageManagerClient,
                 mRankingHandler,
                 mZenModeHelper,
-                new NotificationChannelLoggerImpl());
+                new NotificationChannelLoggerImpl(),
+                mAppOps);
         mRankingHelper = new RankingHelper(getContext(),
                 mRankingHandler,
                 mPreferencesHelper,
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index b3d373f..d432fc8 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -16,7 +16,9 @@
 
 package com.android.server.notification;
 
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
@@ -30,6 +32,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -79,7 +82,9 @@
 
 public class PreferencesHelper implements RankingConfig {
     private static final String TAG = "NotificationPrefHelper";
-    private static final int XML_VERSION = 1;
+    private static final int XML_VERSION = 2;
+    /** What version to check to do the upgrade for bubbles. */
+    private static final int XML_VERSION_BUBBLES_UPGRADE = 1;
     private static final int UNKNOWN_UID = UserHandle.USER_NULL;
     private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
 
@@ -151,6 +156,7 @@
     private final RankingHandler mRankingHandler;
     private final ZenModeHelper mZenModeHelper;
     private final NotificationChannelLogger mNotificationChannelLogger;
+    private final AppOpsManager mAppOps;
 
     private SparseBooleanArray mBadgingEnabled;
     private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE;
@@ -167,12 +173,14 @@
     }
 
     public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
-            ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger) {
+            ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
+            AppOpsManager appOpsManager) {
         mContext = context;
         mZenModeHelper = zenHelper;
         mRankingHandler = rankingHandler;
         mPm = pm;
         mNotificationChannelLogger = notificationChannelLogger;
+        mAppOps = appOpsManager;
 
         // STOPSHIP (b/142218092) this should be removed before ship
         if (!wasBadgingForcedTrue(context)) {
@@ -195,6 +203,15 @@
         if (type != XmlPullParser.START_TAG) return;
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
+
+        boolean upgradeForBubbles = false;
+        if (parser.getAttributeCount() > 0) {
+            String attribute = parser.getAttributeName(0);
+            if (ATT_VERSION.equals(attribute)) {
+                int xmlVersion = Integer.parseInt(parser.getAttributeValue(0));
+                upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
+            }
+        }
         synchronized (mPackagePreferences) {
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 tag = parser.getName();
@@ -220,6 +237,16 @@
                                 }
                             }
                             boolean skipWarningLogged = false;
+                            boolean hasSAWPermission = false;
+                            if (upgradeForBubbles) {
+                                hasSAWPermission = mAppOps.noteOpNoThrow(
+                                        OP_SYSTEM_ALERT_WINDOW, uid, name, null,
+                                        "check-notif-bubble") == AppOpsManager.MODE_ALLOWED;
+                            }
+                            int bubblePref = hasSAWPermission
+                                    ? BUBBLE_PREFERENCE_ALL
+                                    : XmlUtils.readIntAttribute(parser, ATT_ALLOW_BUBBLE,
+                                            DEFAULT_BUBBLE_PREFERENCE);
 
                             PackagePreferences r = getOrCreatePackagePreferencesLocked(
                                     name, userId, uid,
@@ -231,8 +258,7 @@
                                             parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
                                     XmlUtils.readBooleanAttribute(
                                             parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
-                                    XmlUtils.readIntAttribute(
-                                            parser, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE));
+                                    bubblePref);
                             r.importance = XmlUtils.readIntAttribute(
                                     parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                             r.priority = XmlUtils.readIntAttribute(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 59ac603..12ee2f5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -94,6 +94,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -1820,10 +1821,12 @@
                             state.setVerifierResponse(Binder.getCallingUid(),
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                             broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_ALLOW, user);
+                                    PackageManager.VERIFICATION_ALLOW, null, args.mDataLoaderType,
+                                    user);
                         } else {
                             broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_REJECT, user);
+                                    PackageManager.VERIFICATION_REJECT, null, args.mDataLoaderType,
+                                    user);
                             params.setReturnCode(
                                     PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
                             state.setVerifierResponse(Binder.getCallingUid(),
@@ -1899,7 +1902,7 @@
 
                         if (state.isInstallAllowed()) {
                             broadcastPackageVerified(verificationId, originUri,
-                                    response.code, args.getUser());
+                                    response.code, null, args.mDataLoaderType, args.getUser());
                         } else {
                             params.setReturnCode(
                                     PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
@@ -13575,12 +13578,17 @@
     }
 
     private void broadcastPackageVerified(int verificationId, Uri packageUri,
-            int verificationCode, UserHandle user) {
+            int verificationCode, @Nullable String rootHashString, int dataLoaderType,
+            UserHandle user) {
         final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
         intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
         intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
+        if (rootHashString != null) {
+            intent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString);
+        }
+        intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
 
         mContext.sendBroadcastAsUser(intent, user,
                 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
@@ -14952,8 +14960,17 @@
             verificationState.setRequiredVerifierUid(requiredUid);
             final int installerUid =
                     verificationInfo == null ? -1 : verificationInfo.installerUid;
-            if (!origin.existing && isVerificationEnabled(pkgLite, verifierUser.getIdentifier(),
-                      installFlags, installerUid)) {
+            final boolean isVerificationEnabled = isVerificationEnabled(
+                    pkgLite, verifierUser.getIdentifier(), installFlags, installerUid);
+            final boolean isV4Signed =
+                    (mArgs.signingDetails.signatureSchemeVersion == SIGNING_BLOCK_V4);
+            final boolean isIncrementalInstall =
+                    (mArgs.mDataLoaderType == DataLoaderType.INCREMENTAL);
+            // NOTE: We purposefully skip verification for only incremental installs when there's
+            // a v4 signature block. Otherwise, proceed with verification as usual.
+            if (!origin.existing
+                    && isVerificationEnabled
+                    && (!isIncrementalInstall || !isV4Signed)) {
                 final Intent verification = new Intent(
                         Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                 verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -16569,7 +16586,29 @@
             }
             executePostCommitSteps(commitRequest);
         } finally {
-            if (!success) {
+            if (success) {
+                for (InstallRequest request : requests) {
+                    final InstallArgs args = request.args;
+                    if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
+                        continue;
+                    }
+                    if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
+                        continue;
+                    }
+                    // For incremental installs, we bypass the verifier prior to install. Now
+                    // that we know the package is valid, send a notice to the verifier with
+                    // the root hash of the base.apk.
+                    final String baseCodePath = request.installResult.pkg.getBaseCodePath();
+                    final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
+                    final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+                    final int verificationId = mPendingVerificationToken++;
+                    final String rootHashString = PackageManagerServiceUtils
+                            .buildVerificationRootHashString(baseCodePath, splitCodePaths);
+                    broadcastPackageVerified(verificationId, originUri,
+                            PackageManager.VERIFICATION_ALLOW, rootHashString,
+                            args.mDataLoaderType, args.getUser());
+                }
+            } else {
                 for (ScanResult result : preparedScans.values()) {
                     if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
                             false)) {
@@ -16911,7 +16950,6 @@
             if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                 parsedPackage.setSigningDetails(args.signingDetails);
             } else {
-                // TODO(b/136132412): skip for Incremental installation
                 parsedPackage.setSigningDetails(
                         ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 91afd84..5c175a6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -32,7 +32,6 @@
 import android.app.AppGlobals;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -40,7 +39,6 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
-import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
 import android.os.Debug;
 import android.os.Environment;
@@ -50,6 +48,9 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.V4Signature;
+import android.os.incremental.V4Signature.HashingInfo;
 import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -62,6 +63,7 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.HexDump;
 import com.android.server.EventLogTags;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
@@ -94,8 +96,6 @@
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
 
@@ -943,4 +943,71 @@
             Os.chmod(currentDir.getAbsolutePath(), mode);
         }
     }
+
+    /**
+     * Returns a string that's compatible with the verification root hash extra.
+     * @see PackageManager#EXTRA_VERIFICATION_ROOT_HASH
+     */
+    @NonNull
+    public static String buildVerificationRootHashString(@NonNull String baseFilename,
+            @Nullable String[] splitFilenameArray) {
+        final StringBuilder sb = new StringBuilder();
+        final String baseFilePath =
+                baseFilename.substring(baseFilename.lastIndexOf(File.separator) + 1);
+        sb.append(baseFilePath).append(":");
+        final byte[] baseRootHash = getRootHash(baseFilename);
+        if (baseRootHash == null) {
+            sb.append("0");
+        } else {
+            sb.append(HexDump.toHexString(baseRootHash));
+        }
+        if (splitFilenameArray == null || splitFilenameArray.length == 0) {
+            return sb.toString();
+        }
+
+        for (int i = splitFilenameArray.length - 1; i >= 0; i--) {
+            final String splitFilename = splitFilenameArray[i];
+            final String splitFilePath =
+                    splitFilename.substring(splitFilename.lastIndexOf(File.separator) + 1);
+            final byte[] splitRootHash = getRootHash(splitFilename);
+            sb.append(";").append(splitFilePath).append(":");
+            if (splitRootHash == null) {
+                sb.append("0");
+            } else {
+                sb.append(HexDump.toHexString(splitRootHash));
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the root has for the given file.
+     * <p>Otherwise, returns {@code null} if the root hash could not be found or calculated.
+     * <p>NOTE: This currently only works on files stored on the incremental file system. The
+     * eventual goal is that this hash [among others] can be retrieved for any file.
+     */
+    @Nullable
+    private static byte[] getRootHash(String filename) {
+        try {
+            final byte[] baseFileSignature =
+                    IncrementalManager.unsafeGetFileSignature(filename);
+            if (baseFileSignature == null) {
+                throw new IOException("File signature not present");
+            }
+            final V4Signature signature =
+                    V4Signature.readFrom(baseFileSignature);
+            if (signature.hashingInfo == null) {
+                throw new IOException("Hashing info not present");
+            }
+            final HashingInfo hashInfo =
+                    HashingInfo.fromByteArray(signature.hashingInfo);
+            if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) {
+                throw new IOException("Root has not present");
+            }
+            return hashInfo.rawRootHash;
+        } catch (IOException ignore) {
+            Slog.e(TAG, "ERROR: could not load root hash from incremental install");
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a488af7..84cc19d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2445,8 +2445,17 @@
             if (controls != null) {
                 final int length = Math.min(controls.length, outControls.length);
                 for (int i = 0; i < length; i++) {
-                    outControls[i] = win.isClientLocal()
-                            ? new InsetsSourceControl(controls[i]) : controls[i];
+                    final InsetsSourceControl control = controls[i];
+
+                    // Check if we are sending invalid leashes.
+                    final SurfaceControl leash = control != null ? control.getLeash() : null;
+                    if (leash != null && !leash.isValid()) {
+                        Slog.wtf(TAG, leash + " is not valid before sending to " + win,
+                                leash.getReleaseStack());
+                    }
+
+                    outControls[i] = win.isClientLocal() && control != null
+                            ? new InsetsSourceControl(control) : control;
                 }
             }
         }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 427237c..ac51750 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.notification;
 
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
@@ -50,6 +53,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -132,6 +136,7 @@
     @Spy IContentProvider mTestIContentProvider = new MockIContentProvider();
     @Mock Context mContext;
     @Mock ZenModeHelper mMockZenModeHelper;
+    @Mock AppOpsManager mAppOpsManager;
 
     private NotificationManager.Policy mTestNotificationPolicy;
 
@@ -187,7 +192,10 @@
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
+                anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         resetZenModeHelper();
 
         mAudioAttributes = new AudioAttributes.Builder()
@@ -1464,7 +1472,8 @@
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
                 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -1475,7 +1484,8 @@
         // start notification policy off with mAreChannelsBypassingDnd = false
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         assertFalse(mHelper.areChannelsBypassingDnd());
         verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
         resetZenModeHelper();
@@ -2241,7 +2251,8 @@
                 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
                 + "</package>\n"
                 + "</ranking>\n";
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadByteArrayXml(preQXml.getBytes(), true, UserHandle.USER_SYSTEM);
 
         assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2253,7 +2264,8 @@
         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2349,7 +2361,8 @@
         mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2360,7 +2373,8 @@
         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2372,7 +2386,8 @@
         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2384,7 +2399,8 @@
         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // appears disabled
@@ -2402,7 +2418,8 @@
         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // appears disabled
@@ -2417,17 +2434,74 @@
 
     @Test
     public void testBubblePreference_defaults() throws Exception {
-        assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
+        assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
-        assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
+        assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
     }
 
     @Test
+    public void testBubblePreference_upgradeWithSAWPermission() throws Exception {
+        when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
+                anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
+
+        final String xml = "<ranking version=\"1\">\n"
+                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
+                + "<channel id=\"someId\" name=\"hi\""
+                + " importance=\"3\"/>"
+                + "</package>"
+                + "</ranking>";
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+        assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
+        assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+    }
+
+    @Test
+    public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception {
+        when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(),
+                anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED);
+
+        final String xml = "<ranking version=\"1\">\n"
+                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n"
+                + "<channel id=\"someId\" name=\"hi\""
+                + " importance=\"3\"/>"
+                + "</package>"
+                + "</ranking>";
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+        assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
+        assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+
+        mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED);
+        assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
+                mHelper.getAppLockedFields(PKG_O, UID_O));
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
+
+        assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
+                mHelper.getAppLockedFields(PKG_O, UID_O));
+    }
+
+    @Test
     public void testBubblePreference_xml() throws Exception {
         mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
@@ -2435,7 +2509,8 @@
                 mHelper.getAppLockedFields(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
         loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
@@ -2949,7 +3024,8 @@
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
 
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
 
         final String xml = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -2969,7 +3045,8 @@
     public void testPlaceholderConversationId_shortcutRequired() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
 
         final String xml = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -2989,7 +3066,8 @@
     public void testNormalConversationId_shortcutRequired() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
 
         final String xml = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -3009,7 +3087,8 @@
     public void testNoConversationId_shortcutRequired() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
-        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager);
 
         final String xml = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index f4f610b..fa292bd 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -100,7 +100,6 @@
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         setInteractive(false);
-        setLowProfile(true);
         setFullscreen(true);
         setContentView(R.layout.dream);
         setScreenBright(false);