Merge "BAL opt-in Autofill" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 03a23ba..ca73378 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -32,7 +32,6 @@
     cmd: "$(location hoststubgen) " +
         "@$(location ravenwood/ravenwood-standard-options.txt) " +
 
-        "--out-stub-jar $(location ravenwood_stub.jar) " +
         "--out-impl-jar $(location ravenwood.jar) " +
 
         "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " +
@@ -49,7 +48,6 @@
     ],
     out: [
         "ravenwood.jar",
-        "ravenwood_stub.jar", // It's not used. TODO: Update hoststubgen to make it optional.
 
         // Following files are created just as FYI.
         "hoststubgen_keep_all.txt",
diff --git a/core/api/current.txt b/core/api/current.txt
index 591e1b4..812d4cd6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -54187,7 +54187,7 @@
     method public boolean isEnabled();
     method public boolean isFocusable();
     method public boolean isFocused();
-    method public boolean isGranularScrollingSupported();
+    method @FlaggedApi("android.view.accessibility.granular_scrolling") public boolean isGranularScrollingSupported();
     method public boolean isHeading();
     method public boolean isImportantForAccessibility();
     method public boolean isLongClickable();
@@ -54237,7 +54237,7 @@
     method public void setError(CharSequence);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
-    method public void setGranularScrollingSupported(boolean);
+    method @FlaggedApi("android.view.accessibility.granular_scrolling") public void setGranularScrollingSupported(boolean);
     method public void setHeading(boolean);
     method public void setHintText(CharSequence);
     method public void setImportantForAccessibility(boolean);
@@ -54292,7 +54292,7 @@
     field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
     field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
     field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
-    field public static final String ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT = "android.view.accessibility.action.ARGUMENT_SCROLL_AMOUNT_FLOAT";
+    field @FlaggedApi("android.view.accessibility.granular_scrolling") public static final String ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT = "android.view.accessibility.action.ARGUMENT_SCROLL_AMOUNT_FLOAT";
     field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
     field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
     field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
@@ -54395,10 +54395,9 @@
   public static final class AccessibilityNodeInfo.CollectionInfo {
     ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean);
     ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean, int);
-    ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean, int, int, int);
     method public int getColumnCount();
-    method public int getImportantForAccessibilityItemCount();
-    method public int getItemCount();
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") public int getImportantForAccessibilityItemCount();
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") public int getItemCount();
     method public int getRowCount();
     method public int getSelectionMode();
     method public boolean isHierarchical();
@@ -54407,18 +54406,18 @@
     field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
     field public static final int SELECTION_MODE_NONE = 0; // 0x0
     field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
-    field public static final int UNDEFINED = -1; // 0xffffffff
+    field @FlaggedApi("android.view.accessibility.collection_info_item_counts") public static final int UNDEFINED = -1; // 0xffffffff
   }
 
-  public static final class AccessibilityNodeInfo.CollectionInfo.Builder {
-    ctor public AccessibilityNodeInfo.CollectionInfo.Builder();
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo build();
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setColumnCount(int);
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setHierarchical(boolean);
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setImportantForAccessibilityItemCount(int);
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setItemCount(int);
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setRowCount(int);
-    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setSelectionMode(int);
+  @FlaggedApi("android.view.accessibility.collection_info_item_counts") public static final class AccessibilityNodeInfo.CollectionInfo.Builder {
+    ctor @FlaggedApi("android.view.accessibility.collection_info_item_counts") public AccessibilityNodeInfo.CollectionInfo.Builder();
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo build();
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setColumnCount(int);
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setHierarchical(boolean);
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setImportantForAccessibilityItemCount(int);
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setItemCount(int);
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setRowCount(int);
+    method @FlaggedApi("android.view.accessibility.collection_info_item_counts") @NonNull public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo.Builder setSelectionMode(int);
   }
 
   public static final class AccessibilityNodeInfo.CollectionItemInfo {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bb335fa..b5f7f23 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.inMultiWindowMode;
 import static android.os.Process.myUid;
@@ -9439,6 +9440,15 @@
         ActivityClient.getInstance().enableTaskLocaleOverride(mToken);
     }
 
+    /**
+     * Request ActivityRecordInputSink to enable or disable blocking input events.
+     * @hide
+     */
+    @RequiresPermission(INTERNAL_SYSTEM_WINDOW)
+    public void setActivityRecordInputSinkEnabled(boolean enabled) {
+        ActivityClient.getInstance().setActivityRecordInputSinkEnabled(mToken, enabled);
+    }
+
     class HostCallbacks extends FragmentHostCallback<Activity> {
         public HostCallbacks() {
             super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index b35e87b..b8bd030 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.content.ComponentName;
@@ -614,6 +616,15 @@
         }
     }
 
+    @RequiresPermission(INTERNAL_SYSTEM_WINDOW)
+    void setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled) {
+        try {
+            getActivityClientController().setActivityRecordInputSinkEnabled(activityToken, enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Shows or hides a Camera app compat toggle for stretched issues with the requested state.
      *
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index a3c5e1c..7370fc3 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -191,4 +191,14 @@
      */
     boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
             in IBinder taskFragmentToken);
+
+    /**
+     * Enable or disable ActivityRecordInputSink to block input events.
+     *
+     * @param token The token for the activity that requests to toggle.
+     * @param enabled Whether the input evens are blocked by ActivityRecordInputSink.
+     */
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.INTERNAL_SYSTEM_WINDOW)")
+    oneway void setActivityRecordInputSinkEnabled(in IBinder activityToken, boolean enabled);
 }
diff --git a/core/java/android/companion/utils/FeatureUtils.java b/core/java/android/companion/utils/FeatureUtils.java
deleted file mode 100644
index a382e09..0000000
--- a/core/java/android/companion/utils/FeatureUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.companion.utils;
-
-import android.os.Binder;
-import android.os.Build;
-import android.provider.DeviceConfig;
-
-/**
- * Util class for feature flags
- *
- * @hide
- */
-public final class FeatureUtils {
-
-    private static final String NAMESPACE_COMPANION = "companion";
-
-    private static final String PROPERTY_PERM_SYNC_ENABLED = "perm_sync_enabled";
-
-    public static boolean isPermSyncEnabled() {
-        // Permissions sync is always enabled in debuggable mode.
-        if (Build.isDebuggable()) {
-            return true;
-        }
-
-        // Clear app identity to read the device config for feature flag.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return DeviceConfig.getBoolean(NAMESPACE_COMPANION,
-                    PROPERTY_PERM_SYNC_ENABLED, false);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private FeatureUtils() {
-    }
-}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 89f889f..fe95a2a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1414,7 +1414,7 @@
      * otherwise the value will be equal to 1.
      * Note that this level is just a number of supported levels (the granularity of control).
      * There is no actual physical power units tied to this level.</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#FLASH_MODE
      */
@@ -1430,7 +1430,7 @@
      * or equal to <code>android.flash.info.singleStrengthMaxLevel</code>.
      * Note for devices that do not support the manual flash strength control
      * feature, this level will always be equal to 1.</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      */
     @PublicKey
     @NonNull
@@ -1450,7 +1450,7 @@
      * android.flash.info.singleStrengthMaxLevel i.e. the ratio of
      * android.flash.info.torchStrengthMaxLevel:android.flash.info.singleStrengthMaxLevel
      * is not guaranteed to be the ratio of actual brightness.</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#FLASH_MODE
      */
@@ -1466,7 +1466,7 @@
      * or equal to android.flash.info.torchStrengthMaxLevel.
      * Note for the devices that do not support the manual flash strength control feature,
      * this level will always be equal to 1.</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      */
     @PublicKey
     @NonNull
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5d06978..93cae54 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2688,7 +2688,7 @@
      * set to TORCH;
      * <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
      * set to SINGLE</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#FLASH_MODE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0d204f3..12ab0f6 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2974,7 +2974,7 @@
      * set to TORCH;
      * <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
      * set to SINGLE</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#FLASH_MODE
diff --git a/core/java/android/permission/IOnPermissionsChangeListener.aidl b/core/java/android/permission/IOnPermissionsChangeListener.aidl
index afacf1a..c68c0c9 100644
--- a/core/java/android/permission/IOnPermissionsChangeListener.aidl
+++ b/core/java/android/permission/IOnPermissionsChangeListener.aidl
@@ -21,5 +21,5 @@
  * {@hide}
  */
 oneway interface IOnPermissionsChangeListener {
-    void onPermissionsChanged(int uid, String deviceId);
+    void onPermissionsChanged(int uid, String persistentDeviceId);
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 7a158c5..91adc37 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1738,8 +1738,9 @@
         }
 
         @Override
-        public void onPermissionsChanged(int uid, String deviceId) {
-            mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget();
+        public void onPermissionsChanged(int uid, String persistentDeviceId) {
+            mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId)
+                    .sendToTarget();
         }
 
         @Override
@@ -1747,8 +1748,8 @@
             switch (msg.what) {
                 case MSG_PERMISSIONS_CHANGED: {
                     final int uid = msg.arg1;
-                    final String deviceId = msg.obj.toString();
-                    mListener.onPermissionsChanged(uid, deviceId);
+                    final String persistentDeviceId = msg.obj.toString();
+                    mListener.onPermissionsChanged(uid, persistentDeviceId);
                     return true;
                 }
                 default:
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
index bb0e6ab..cb0b5fa 100644
--- a/core/java/android/service/notification/OWNERS
+++ b/core/java/android/service/notification/OWNERS
@@ -2,6 +2,7 @@
 
 juliacr@google.com
 yurilin@google.com
+matiashe@google.com
 jeffdq@google.com
 dsandler@android.com
 dsandler@google.com
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 43bfe13..53aed49 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -23,7 +23,7 @@
 
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.Hide;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -752,6 +752,7 @@
      *     {@link #isGranularScrollingSupported()} to check if granular scrolling is supported.
      * </p>
      */
+    @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING)
     public static final String ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT =
             "android.view.accessibility.action.ARGUMENT_SCROLL_AMOUNT_FLOAT";
 
@@ -2608,6 +2609,7 @@
      * @return True if all scroll actions that could support
      * {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT} have done so, false otherwise.
      */
+    @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING)
     public boolean isGranularScrollingSupported() {
         return getBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING);
     }
@@ -2626,6 +2628,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
+    @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING)
     public void setGranularScrollingSupported(boolean granularScrollingSupported) {
         setBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING,
                 granularScrollingSupported);
@@ -6119,6 +6122,7 @@
          * This should be used for {@code mItemCount} and
          * {@code mImportantForAccessibilityItemCount} when values for those fields are not known.
          */
+        @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
         public static final int UNDEFINED = -1;
 
         private int mRowCount;
@@ -6229,8 +6233,8 @@
          *                  the item count is not known.
          * @param importantForAccessibilityItemCount The count of the collection's views considered
          *                                           important for accessibility.
+         * @hide
          */
-        @Hide
         public CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
                 int selectionMode, int itemCount, int importantForAccessibilityItemCount) {
             mRowCount = rowCount;
@@ -6287,6 +6291,7 @@
          *
          * @return The count of items, which may be {@code UNDEFINED} if the count is not known.
          */
+        @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
         public int getItemCount() {
             return mItemCount;
         }
@@ -6297,6 +6302,7 @@
          * @return The count of items important for accessibility, which may be {@code UNDEFINED}
          * if the count is not known.
          */
+        @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
         public int getImportantForAccessibilityItemCount() {
             return mImportantForAccessibilityItemCount;
         }
@@ -6323,6 +6329,7 @@
          * The builder for CollectionInfo.
          */
 
+        @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
         public static final class Builder {
             private int mRowCount = 0;
             private int mColumnCount = 0;
@@ -6334,6 +6341,7 @@
             /**
              * Creates a new Builder.
              */
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public Builder() {
             }
 
@@ -6343,6 +6351,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setRowCount(int rowCount) {
                 mRowCount = rowCount;
                 return this;
@@ -6354,6 +6363,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setColumnCount(int columnCount) {
                 mColumnCount = columnCount;
                 return this;
@@ -6364,6 +6374,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setHierarchical(boolean hierarchical) {
                 mHierarchical = hierarchical;
                 return this;
@@ -6375,6 +6386,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setSelectionMode(int selectionMode) {
                 mSelectionMode = selectionMode;
                 return this;
@@ -6389,6 +6401,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setItemCount(int itemCount) {
                 mItemCount = itemCount;
                 return this;
@@ -6401,6 +6414,7 @@
              * @return This builder.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo.Builder setImportantForAccessibilityItemCount(
                     int importantForAccessibilityItemCount) {
                 mImportantForAccessibilityItemCount = importantForAccessibilityItemCount;
@@ -6411,6 +6425,7 @@
              * Creates a new {@link CollectionInfo} instance.
              */
             @NonNull
+            @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS)
             public CollectionInfo build() {
                 CollectionInfo collectionInfo = new CollectionInfo(mRowCount, mColumnCount,
                         mHierarchical);
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 950fa4b..c337cb4 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -17,6 +17,13 @@
 }
 
 flag {
+    namespace: "accessibility"
+    name: "collection_info_item_counts"
+    description: "Fields for total items and the number of important for accessibility items in a collection"
+    bug: "302376158"
+}
+
+flag {
     name: "deduplicate_accessibility_warning_dialog"
     namespace: "accessibility"
     description: "Removes duplicate definition of the accessibility warning dialog."
@@ -39,6 +46,13 @@
 
 flag {
     namespace: "accessibility"
+    name: "granular_scrolling"
+    description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
+    bug: "302376158"
+}
+
+flag {
+    namespace: "accessibility"
     name: "update_always_on_a11y_service"
     description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut."
     bug: "298869916"
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 11bd22f..0da03fb 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -39,4 +39,12 @@
     description: "Remove uses of ScreenCapture#captureDisplay"
     is_fixed_read_only: true
     bug: "293445881"
-}
\ No newline at end of file
+}
+
+flag {
+    namespace: "window_surfaces"
+    name: "allow_disable_activity_record_input_sink"
+    description: "Whether to allow system activity to disable ActivityRecordInputSink"
+    is_fixed_read_only: true
+    bug: "262477923"
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index c7ab6aa..f5b877a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -963,7 +963,11 @@
                 && mTaskView.isAttachedToWindow()) {
             // post this to the looper, because if the device orientation just changed, we need to
             // let the current shell transition complete before updating the task view bounds.
-            post(() -> mTaskView.onLocationChanged());
+            post(() -> {
+                if (mTaskView != null) {
+                    mTaskView.onLocationChanged();
+                }
+            });
         }
         if (mIsOverflow) {
             // post this to the looper so that the view has a chance to be laid out before it can
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 27dc870..b158f88 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -250,10 +250,10 @@
             SyncTransactionQueue syncQueue,
             @ShellMainThread ShellExecutor mainExecutor,
             Lazy<Transitions> transitionsLazy,
-            DockStateReader dockStateReader,
-            CompatUIConfiguration compatUIConfiguration,
-            CompatUIShellCommandHandler compatUIShellCommandHandler,
-            AccessibilityManager accessibilityManager) {
+            Lazy<DockStateReader> dockStateReader,
+            Lazy<CompatUIConfiguration> compatUIConfiguration,
+            Lazy<CompatUIShellCommandHandler> compatUIShellCommandHandler,
+            Lazy<AccessibilityManager> accessibilityManager) {
         if (!context.getResources().getBoolean(R.bool.config_enableCompatUIController)) {
             return Optional.empty();
         }
@@ -268,10 +268,10 @@
                         syncQueue,
                         mainExecutor,
                         transitionsLazy,
-                        dockStateReader,
-                        compatUIConfiguration,
-                        compatUIShellCommandHandler,
-                        accessibilityManager));
+                        dockStateReader.get(),
+                        compatUIConfiguration.get(),
+                        compatUIShellCommandHandler.get(),
+                        accessibilityManager.get()));
     }
 
     @WMSingleton
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d056248..8748dab 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -603,7 +603,7 @@
     std::unique_ptr<Asset> asset = assets->GetAssetsProvider()->Open(filename, mode);
     if (asset) {
       if (out_cookie != nullptr) {
-        *out_cookie = i;
+        *out_cookie = i - 1;
       }
       return asset;
     }
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index b63ee1b..a9d1a2a 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -25,8 +25,9 @@
 
 #include "MinikinSkia.h"
 #include "SkPaint.h"
-#include "SkStream.h"  // Fot tests.
+#include "SkStream.h"  // For tests.
 #include "SkTypeface.h"
+#include "utils/TypefaceUtils.h"
 
 #include <minikin/FontCollection.h>
 #include <minikin/FontFamily.h>
@@ -186,7 +187,9 @@
     LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", kRobotoFont);
     void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
     std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data, st.st_size));
-    sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(std::move(fontData));
+    sk_sp<SkFontMgr> fm = android::FreeTypeFontMgr();
+    LOG_ALWAYS_FATAL_IF(fm == nullptr, "Could not load FreeType SkFontMgr");
+    sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(fontData));
     LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
 
     std::shared_ptr<minikin::MinikinFont> font =
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index de842e6..9f63dfd 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1065,17 +1065,8 @@
      * @see #isVolumeFixed()
      */
     public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
-        if (autoPublicVolumeApiHardening()) {
-            final IAudioService service = getService();
-            try {
-                service.adjustVolume(direction, flags);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        } else {
-            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
-            helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+        helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
     }
 
     /**
@@ -1104,17 +1095,8 @@
      */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
             @PublicVolumeFlags int flags) {
-        if (autoPublicVolumeApiHardening()) {
-            final IAudioService service = getService();
-            try {
-                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        } else {
-            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
-            helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+        helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
     }
 
     /** @hide */
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 11e3a08..b4ca485 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -500,10 +500,6 @@
             in String packageName, int uid, int pid, in UserHandle userHandle,
             int targetSdkVersion);
 
-    oneway void adjustVolume(int direction, int flags);
-
-    oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
-
     boolean isMusicActive(in boolean remotely);
 
     int getDeviceMaskForStream(in int streamType);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
index f83e37b..3774b88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
@@ -37,9 +37,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-/**
- * VolumeControlProfile handles Bluetooth Volume Control Controller role
- */
+/** VolumeControlProfile handles Bluetooth Volume Control Controller role */
 public class VolumeControlProfile implements LocalBluetoothProfile {
     private static final String TAG = "VolumeControlProfile";
     private static boolean DEBUG = true;
@@ -77,8 +75,8 @@
                     }
                     device = mDeviceManager.addDevice(nextDevice);
                 }
-                device.onProfileStateChanged(VolumeControlProfile.this,
-                        BluetoothProfile.STATE_CONNECTED);
+                device.onProfileStateChanged(
+                        VolumeControlProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
             }
 
@@ -95,32 +93,36 @@
         }
     }
 
-    VolumeControlProfile(Context context, CachedBluetoothDeviceManager deviceManager,
+    VolumeControlProfile(
+            Context context,
+            CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
         mContext = context;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
 
-        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
-                new VolumeControlProfile.VolumeControlProfileServiceListener(),
-                BluetoothProfile.VOLUME_CONTROL);
+        BluetoothAdapter.getDefaultAdapter()
+                .getProfileProxy(
+                        context,
+                        new VolumeControlProfile.VolumeControlProfileServiceListener(),
+                        BluetoothProfile.VOLUME_CONTROL);
     }
 
-
     /**
-     * Registers a {@link BluetoothVolumeControl.Callback} that will be invoked during the
-     * operation of this profile.
+     * Registers a {@link BluetoothVolumeControl.Callback} that will be invoked during the operation
+     * of this profile.
      *
-     * Repeated registration of the same <var>callback</var> object will have no effect after
-     * the first call to this method, even when the <var>executor</var> is different. API caller
-     * would have to call {@link #unregisterCallback(BluetoothVolumeControl.Callback)} with
-     * the same callback object before registering it again.
+     * <p>Repeated registration of the same <var>callback</var> object will have no effect after the
+     * first call to this method, even when the <var>executor</var> is different. API caller would
+     * have to call {@link #unregisterCallback(BluetoothVolumeControl.Callback)} with the same
+     * callback object before registering it again.
      *
      * @param executor an {@link Executor} to execute given callback
      * @param callback user implementation of the {@link BluetoothVolumeControl.Callback}
      * @throws IllegalArgumentException if a null executor or callback is given
      */
-    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+    public void registerCallback(
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull BluetoothVolumeControl.Callback callback) {
         if (mService == null) {
             Log.w(TAG, "Proxy not attached to service. Cannot register callback.");
@@ -131,8 +133,9 @@
 
     /**
      * Unregisters the specified {@link BluetoothVolumeControl.Callback}.
-     * <p>The same {@link BluetoothVolumeControl.Callback} object used when calling
-     * {@link #registerCallback(Executor, BluetoothVolumeControl.Callback)} must be used.
+     *
+     * <p>The same {@link BluetoothVolumeControl.Callback} object used when calling {@link
+     * #registerCallback(Executor, BluetoothVolumeControl.Callback)} must be used.
      *
      * <p>Callbacks are automatically unregistered when application process goes away
      *
@@ -153,8 +156,8 @@
      * @param device {@link BluetoothDevice} representing the remote device
      * @param volumeOffset volume offset to be set on the remote device
      */
-    public void setVolumeOffset(BluetoothDevice device,
-            @IntRange(from = -255, to = 255) int volumeOffset) {
+    public void setVolumeOffset(
+            BluetoothDevice device, @IntRange(from = -255, to = 255) int volumeOffset) {
         if (mService == null) {
             Log.w(TAG, "Proxy not attached to service. Cannot set volume offset.");
             return;
@@ -165,16 +168,13 @@
         }
         mService.setVolumeOffset(device, volumeOffset);
     }
-
     /**
-     * Provides information about the possibility to set volume offset on the remote device.
-     * If the remote device supports Volume Offset Control Service, it is automatically
-     * connected.
+     * Provides information about the possibility to set volume offset on the remote device. If the
+     * remote device supports Volume Offset Control Service, it is automatically connected.
      *
      * @param device {@link BluetoothDevice} representing the remote device
      * @return {@code true} if volume offset function is supported and available to use on the
-     *         remote device. When Bluetooth is off, the return value should always be
-     *         {@code false}.
+     *     remote device. When Bluetooth is off, the return value should always be {@code false}.
      */
     public boolean isVolumeOffsetAvailable(BluetoothDevice device) {
         if (mService == null) {
@@ -188,6 +188,28 @@
         return mService.isVolumeOffsetAvailable(device);
     }
 
+    /**
+     * Tells the remote device to set a volume.
+     *
+     * @param device {@link BluetoothDevice} representing the remote device
+     * @param volume volume to be set on the remote device
+     * @param isGroupOp whether to set the volume to remote devices within the same CSIP group
+     */
+    public void setDeviceVolume(
+            BluetoothDevice device,
+            @IntRange(from = 0, to = 255) int volume,
+            boolean isGroupOp) {
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service. Cannot set volume offset.");
+            return;
+        }
+        if (device == null) {
+            Log.w(TAG, "Device is null. Cannot set volume offset.");
+            return;
+        }
+        mService.setDeviceVolume(device, volume, isGroupOp);
+    }
+
     @Override
     public boolean accessProfileEnabled() {
         return false;
@@ -199,10 +221,9 @@
     }
 
     /**
-     * Gets VolumeControlProfile devices matching connection states{
-     * {@code BluetoothProfile.STATE_CONNECTED},
-     * {@code BluetoothProfile.STATE_CONNECTING},
-     * {@code BluetoothProfile.STATE_DISCONNECTING}}
+     * Gets VolumeControlProfile devices matching connection states{ {@code
+     * BluetoothProfile.STATE_CONNECTED}, {@code BluetoothProfile.STATE_CONNECTING}, {@code
+     * BluetoothProfile.STATE_DISCONNECTING}}
      *
      * @return Matching device list
      */
@@ -211,8 +232,11 @@
             return new ArrayList<BluetoothDevice>(0);
         }
         return mService.getDevicesMatchingConnectionStates(
-                new int[]{BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
-                        BluetoothProfile.STATE_DISCONNECTING});
+                new int[] {
+                    BluetoothProfile.STATE_CONNECTED,
+                    BluetoothProfile.STATE_CONNECTING,
+                    BluetoothProfile.STATE_DISCONNECTING
+                });
     }
 
     @Override
@@ -285,7 +309,7 @@
 
     @Override
     public int getSummaryResourceForDevice(BluetoothDevice device) {
-        return 0;   // VCP profile not displayed in UI
+        return 0; // VCP profile not displayed in UI
     }
 
     @Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
index c560627..fe1529d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
@@ -54,18 +54,14 @@
 public class VolumeControlProfileTest {
 
     private static final int TEST_VOLUME_OFFSET = 10;
+    private static final int TEST_VOLUME_VALUE = 10;
 
-    @Rule
-    public final MockitoRule mockito = MockitoJUnit.rule();
+    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
 
-    @Mock
-    private CachedBluetoothDeviceManager mDeviceManager;
-    @Mock
-    private LocalBluetoothProfileManager mProfileManager;
-    @Mock
-    private BluetoothDevice mBluetoothDevice;
-    @Mock
-    private BluetoothVolumeControl mService;
+    @Mock private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock private LocalBluetoothProfileManager mProfileManager;
+    @Mock private BluetoothDevice mBluetoothDevice;
+    @Mock private BluetoothVolumeControl mService;
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private BluetoothProfile.ServiceListener mServiceListener;
@@ -177,14 +173,14 @@
     @Test
     public void getConnectedDevices_returnCorrectList() {
         mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
-        int[] connectedStates = new int[] {
-                BluetoothProfile.STATE_CONNECTED,
-                BluetoothProfile.STATE_CONNECTING,
-                BluetoothProfile.STATE_DISCONNECTING};
-        List<BluetoothDevice> connectedList = Arrays.asList(
-                mBluetoothDevice,
-                mBluetoothDevice,
-                mBluetoothDevice);
+        int[] connectedStates =
+                new int[] {
+                    BluetoothProfile.STATE_CONNECTED,
+                    BluetoothProfile.STATE_CONNECTING,
+                    BluetoothProfile.STATE_DISCONNECTING
+                };
+        List<BluetoothDevice> connectedList =
+                Arrays.asList(mBluetoothDevice, mBluetoothDevice, mBluetoothDevice);
         when(mService.getDevicesMatchingConnectionStates(connectedStates))
                 .thenReturn(connectedList);
 
@@ -222,6 +218,16 @@
     }
 
     @Test
+    public void setDeviceVolume_verifyIsCalled() {
+        mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
+
+        mProfile.setDeviceVolume(mBluetoothDevice, TEST_VOLUME_VALUE, /* isGroupOp= */ true);
+
+        verify(mService)
+                .setDeviceVolume(mBluetoothDevice, TEST_VOLUME_VALUE, /* isGroupOp= */ true);
+    }
+
+    @Test
     public void isVolumeOffsetAvailable_verifyIsCalledAndReturnTrue() {
         mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
         when(mService.isVolumeOffsetAvailable(mBluetoothDevice)).thenReturn(true);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9ab9ba8..d78038e 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -224,11 +224,6 @@
         extra_check_modules: ["SystemUILintChecker"],
         warning_checks: ["MissingApacheLicenseDetector"],
     },
-    errorprone: {
-        javacflags: [
-            "-Xep:InvalidPatternSyntax:WARN",
-        ],
-    },
 }
 
 filegroup {
@@ -553,11 +548,6 @@
         test: true,
         extra_check_modules: ["SystemUILintChecker"],
     },
-    errorprone: {
-        javacflags: [
-            "-Xep:InvalidPatternSyntax:WARN",
-        ],
-    },
 }
 
 android_app {
@@ -599,12 +589,6 @@
     },
 
     plugins: ["dagger2-compiler"],
-
-    errorprone: {
-        javacflags: [
-            "-Xep:InvalidPatternSyntax:WARN",
-        ],
-    },
 }
 
 android_robolectric_test {
diff --git a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
index 952f056..cc99f5e 100644
--- a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
+++ b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
@@ -22,13 +22,15 @@
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
     android:gravity="center_vertical"
-    android:orientation="horizontal" >
+    android:orientation="horizontal"
+    android:theme="@style/Theme.SystemUI.QuickSettings.Header" >
 
     <com.android.systemui.util.AutoMarqueeTextView
         android:id="@+id/mobile_carrier_text"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
+        android:textAppearance="@style/TextAppearance.QS.Status.Carriers"
         android:layout_marginEnd="@dimen/qs_carrier_margin_width"
         android:visibility="gone"
         android:textDirection="locale"
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 355e75d..9c08f5e 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -18,7 +18,7 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         android:color="?android:attr/colorControlHighlight">
-    <item>
+    <item android:id="@+id/notification_background_color_layer">
         <shape>
             <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
         </shape>
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 98fda3e..1710a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -707,7 +707,7 @@
 
     /** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
     @JvmField
-    val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog")
+    val BLUETOOTH_QS_TILE_DIALOG = releasedFlag("bluetooth_qs_tile_dialog")
 
     // TODO(b/300995746): Tracking Bug
     /** A resource flag for whether the communal service is enabled. */
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 58c4f0d..ef72967 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -131,6 +131,9 @@
                     + "\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})"
                     + "?)*";
 
+    // Not all JDKs support emoji patterns, including the one errorprone runs under, which
+    // makes it think that this is an invalid pattern.
+    @SuppressWarnings("InvalidPatternSyntax")
     static final Pattern EMOJI_PATTERN = Pattern.compile(UNICODE_EMOJI_REGEX);
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 8eda96f..64f61d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -27,6 +27,7 @@
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 
 import androidx.annotation.NonNull;
@@ -42,9 +43,11 @@
  * A view that can be used for both the dimmed and normal background of an notification.
  */
 public class NotificationBackgroundView extends View implements Dumpable {
+    private static final String TAG = "NotificationBackgroundView";
 
     private final boolean mDontModifyCorners;
     private Drawable mBackground;
+    private Drawable mBackgroundDrawableToTint;
     private int mClipTopAmount;
     private int mClipBottomAmount;
     private int mTintColor;
@@ -131,6 +134,7 @@
             unscheduleDrawable(mBackground);
         }
         mBackground = background;
+        mBackgroundDrawableToTint = findBackgroundDrawableToTint(mBackground);
         mRippleColor = null;
         mBackground.mutate();
         if (mBackground != null) {
@@ -144,25 +148,46 @@
         invalidate();
     }
 
+    // setCustomBackground should be called from ActivatableNotificationView.initBackground
+    // with R.drawable.notification_material_bg, which is a layer-list with a lower layer
+    // for the background color (annotated with an ID so we can find it) and an upper layer
+    // to blend in the stateful @color/notification_overlay_color.
+    //
+    // If the notification is tinted, we want to set a tint list on *just that lower layer* that
+    // will replace the default materialColorSurfaceContainerHigh *without* wiping out the stateful
+    // tints in the upper layer that make the hovered and pressed states visible.
+    //
+    // This function fishes that lower layer out, or makes a fuss in logcat if it can't find it.
+    private @Nullable Drawable findBackgroundDrawableToTint(@Nullable Drawable background) {
+        if (background == null) {
+            return null;
+        }
+
+        if (!(background instanceof LayerDrawable)) {
+            Log.wtf(TAG, "background is not a LayerDrawable: " + background);
+            return background;
+        }
+
+        final Drawable backgroundColorLayer = ((LayerDrawable) background).findDrawableByLayerId(
+                R.id.notification_background_color_layer);
+
+        if (backgroundColorLayer == null) {
+            Log.wtf(TAG, "background is missing background color layer: " + background);
+            return background;
+        }
+
+        return backgroundColorLayer;
+    }
+
     public void setCustomBackground(int drawableResId) {
         final Drawable d = mContext.getDrawable(drawableResId);
         setCustomBackground(d);
     }
 
     public void setTint(int tintColor) {
-        if (tintColor != 0) {
-            ColorStateList stateList = new ColorStateList(new int[][]{
-                    new int[]{com.android.internal.R.attr.state_pressed},
-                    new int[]{com.android.internal.R.attr.state_hovered},
-                    new int[]{}},
+        mBackgroundDrawableToTint.setTint(tintColor);
+        mBackgroundDrawableToTint.setTintMode(PorterDuff.Mode.SRC_ATOP);
 
-                    new int[]{tintColor, tintColor, tintColor}
-            );
-            mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP);
-            mBackground.setTintList(stateList);
-        } else {
-            mBackground.setTintList(null);
-        }
         mTintColor = tintColor;
         invalidate();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 61a79b7..6944453 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -565,6 +565,7 @@
     private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
     private final ScreenOffAnimationController mScreenOffAnimationController;
     private boolean mShouldUseSplitNotificationShade;
+    private boolean mShouldSkipTopPaddingAnimationAfterFold = false;
     private boolean mHasFilteredOutSeenNotifications;
     @Nullable private SplitShadeStateController mSplitShadeStateController = null;
     private boolean mIsSmallLandscapeLockscreenEnabled = false;
@@ -1364,7 +1365,11 @@
             mTopPadding = topPadding;
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
-            if (shouldAnimate && mAnimationsEnabled && mIsExpanded) {
+            if (mAmbientState.isOnKeyguard()
+                    && !mShouldUseSplitNotificationShade
+                    && mShouldSkipTopPaddingAnimationAfterFold) {
+                mShouldSkipTopPaddingAnimationAfterFold = false;
+            } else if (shouldAnimate && mAnimationsEnabled && mIsExpanded) {
                 mTopPaddingNeedsAnimation = true;
                 mNeedsAnimation = true;
             }
@@ -5741,6 +5746,7 @@
         boolean split = mSplitShadeStateController.shouldUseSplitNotificationShade(getResources());
         if (split != mShouldUseSplitNotificationShade) {
             mShouldUseSplitNotificationShade = split;
+            mShouldSkipTopPaddingAnimationAfterFold = true;
             mAmbientState.setUseSplitShade(split);
             updateDismissBehavior();
             updateUseRoundedRectClipping();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index 1c7fd56..7361f6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -18,7 +18,6 @@
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE
@@ -37,7 +36,7 @@
 @RunWith(AndroidTestingRunner::class)
 class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
     init {
-        setFlagsRule.disableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR)
+        mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME)
     }
 
     override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index df6f0d7..d2c046c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -18,7 +18,6 @@
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK
@@ -30,7 +29,7 @@
 @RunWith(AndroidTestingRunner::class)
 class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() {
     init {
-        setFlagsRule.enableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR)
+        mSetFlagsRule.enableFlags(VisualInterruptionRefactor.FLAG_NAME)
     }
 
     override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 7babff5..2ac0cb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -44,7 +44,6 @@
 import android.hardware.display.FakeAmbientDisplayConfiguration
 import android.os.Looper
 import android.os.PowerManager
-import android.platform.test.flag.junit.SetFlagsRule
 import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED
 import android.provider.Settings.Global.HEADS_UP_OFF
 import android.provider.Settings.Global.HEADS_UP_ON
@@ -84,15 +83,10 @@
 import junit.framework.Assert.assertTrue
 import org.junit.Assert.assertEquals
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.mockito.Mockito.`when` as whenever
 
 abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
-    @JvmField
-    @Rule
-    val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
-
     private val fakeLogBuffer =
         LogBuffer(
             name = "FakeLog",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 4b1c7e8..4422764 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -157,6 +157,7 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper;
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -347,6 +348,8 @@
         mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
         mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
+        // TODO: b/312476335 - Update to check flag and instantiate old or new implementation.
+        mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME);
 
         IThermalService thermalService = mock(IThermalService.class);
         mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index df7609c..200cfd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -146,6 +146,7 @@
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper;
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
@@ -366,6 +367,9 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        // TODO: b/312476335 - Update to check flag and instantiate old or new implementation.
+        mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME);
+
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             doReturn(true).when(mTransitions).isRegistered();
         }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index b9c269c..71a1f01 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -75,7 +75,6 @@
 import android.companion.IOnTransportsChangedListener;
 import android.companion.ISystemDataTransferCallback;
 import android.companion.datatransfer.PermissionSyncRequest;
-import android.companion.utils.FeatureUtils;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -829,11 +828,6 @@
         @Override
         public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,
                 int userId, int associationId) {
-            if (!FeatureUtils.isPermSyncEnabled()) {
-                throw new UnsupportedOperationException("Calling"
-                        + " buildPermissionTransferUserConsentIntent, but this API is disabled by"
-                        + " the system.");
-            }
             return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent(
                     packageName, userId, associationId);
         }
@@ -841,10 +835,6 @@
         @Override
         public void startSystemDataTransfer(String packageName, int userId, int associationId,
                 ISystemDataTransferCallback callback) {
-            if (!FeatureUtils.isPermSyncEnabled()) {
-                throw new UnsupportedOperationException("Calling startSystemDataTransfer, but this"
-                        + " API is disabled by the system.");
-            }
             mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId,
                     associationId, callback);
         }
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 7907d61..77b6d583 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -1182,8 +1182,8 @@
 
         // we are only interested in doing things at PHASE_BOOT_COMPLETED
         if (phase == PHASE_BOOT_COMPLETED) {
-            Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
-            getVBMetaDigestInformation();
+            Slog.i(TAG, "Boot completed. Getting boot integrity data.");
+            collectBootIntegrityInfo();
 
             // Log to statsd
             // TODO(b/264061957): For now, biometric system properties are always collected if users
@@ -1458,10 +1458,19 @@
         }
     }
 
-    private void getVBMetaDigestInformation() {
+    private void collectBootIntegrityInfo() {
         mVbmetaDigest = SystemProperties.get(SYSPROP_NAME_VBETA_DIGEST, VBMETA_DIGEST_UNAVAILABLE);
         Slog.d(TAG, String.format("VBMeta Digest: %s", mVbmetaDigest));
         FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
+
+        if (android.security.Flags.binaryTransparencySepolicyHash()) {
+            byte[] sepolicyHash = PackageUtils.computeSha256DigestForLargeFileAsBytes(
+                    "/sys/fs/selinux/policy", PackageUtils.createLargeFileBuffer());
+            String sepolicyHashEncoded = HexEncoding.encodeToString(sepolicyHash, false);
+            Slog.d(TAG, "sepolicy hash: " + sepolicyHashEncoded);
+            FrameworkStatsLog.write(FrameworkStatsLog.BOOT_INTEGRITY_INFO_REPORTED,
+                    sepolicyHashEncoded, mVbmetaDigest);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5b54561..e07631c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -193,6 +193,12 @@
     private @Nullable BroadcastProcessQueue mRunningColdStart;
 
     /**
+     * Indicates whether we have queued a message to check pending cold start validity.
+     */
+    @GuardedBy("mService")
+    private boolean mCheckPendingColdStartQueued;
+
+    /**
      * Collection of latches waiting for device to reach specific state. The
      * first argument is a function to test for the desired state, and the
      * second argument is the latch to release once that state is reached.
@@ -302,7 +308,11 @@
                 return true;
             }
             case MSG_CHECK_PENDING_COLD_START_VALIDITY: {
-                checkPendingColdStartValidity();
+                synchronized (mService) {
+                    /* Clear this as we have just received the broadcast. */
+                    mCheckPendingColdStartQueued = false;
+                    checkPendingColdStartValidityLocked();
+                }
                 return true;
             }
             case MSG_PROCESS_FREEZABLE_CHANGED: {
@@ -549,7 +559,7 @@
             mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
         }
 
-        checkPendingColdStartValidity();
+        checkPendingColdStartValidityLocked();
         checkAndRemoveWaitingFor();
 
         traceEnd(cookie);
@@ -573,22 +583,24 @@
         enqueueUpdateRunningList();
     }
 
-    private void checkPendingColdStartValidity() {
+    @GuardedBy("mService")
+    private void checkPendingColdStartValidityLocked() {
         // There are a few cases where a starting process gets killed but AMS doesn't report
         // this event. So, once we start waiting for a pending cold start, periodically check
         // if the pending start is still valid and if not, clear it so that the queue doesn't
         // keep waiting for the process start forever.
-        synchronized (mService) {
-            // If there is no pending cold start, then nothing to do.
-            if (mRunningColdStart == null) {
-                return;
-            }
-            if (isPendingColdStartValid()) {
+        // If there is no pending cold start, then nothing to do.
+        if (mRunningColdStart == null) {
+            return;
+        }
+        if (isPendingColdStartValid()) {
+            if (!mCheckPendingColdStartQueued) {
                 mLocalHandler.sendEmptyMessageDelayed(MSG_CHECK_PENDING_COLD_START_VALIDITY,
                         mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS);
-            } else {
-                clearInvalidPendingColdStart();
+                mCheckPendingColdStartQueued = true;
             }
+        } else {
+            clearInvalidPendingColdStart();
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1ef4333..df106a7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -154,7 +154,6 @@
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionCallback;
 import android.media.projection.IMediaProjectionManager;
-import android.media.session.MediaSessionManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -312,9 +311,6 @@
     private final ContentResolver mContentResolver;
     private final AppOpsManager mAppOps;
 
-    /** do not use directly, use getMediaSessionManager() which handles lazy initialization */
-    @Nullable private volatile MediaSessionManager mMediaSessionManager;
-
     // the platform type affects volume and silent mode behavior
     private final int mPlatformType;
 
@@ -945,8 +941,6 @@
 
     private final SoundDoseHelper mSoundDoseHelper;
 
-    private final HardeningEnforcer mHardeningEnforcer;
-
     private final Object mSupportedSystemUsagesLock = new Object();
     @GuardedBy("mSupportedSystemUsagesLock")
     private @AttributeSystemUsage int[] mSupportedSystemUsages =
@@ -1321,8 +1315,6 @@
         mDisplayManager = context.getSystemService(DisplayManager.class);
 
         mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
-
-        mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive());
     }
 
     private void initVolumeStreamStates() {
@@ -1394,6 +1386,7 @@
 
         // check on volume initialization
         checkVolumeRangeInitialization("AudioService()");
+
     }
 
     private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener =
@@ -1406,14 +1399,6 @@
                 }
             };
 
-    private MediaSessionManager getMediaSessionManager() {
-        if (mMediaSessionManager == null) {
-            mMediaSessionManager = (MediaSessionManager) mContext
-                    .getSystemService(Context.MEDIA_SESSION_SERVICE);
-        }
-        return mMediaSessionManager;
-    }
-
     /**
      * Initialize intent receives and settings observers for this service.
      * Must be called after createStreamStates() as the handling of some events
@@ -3442,10 +3427,6 @@
      * Part of service interface, check permissions here */
     public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags,
             String callingPackage, String attributionTag) {
-        if (mHardeningEnforcer.blockVolumeMethod(
-                HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME)) {
-            return;
-        }
         if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
             Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
                     + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
@@ -4222,10 +4203,6 @@
      * Part of service interface, check permissions here */
     public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
             String callingPackage, String attributionTag) {
-        if (mHardeningEnforcer.blockVolumeMethod(
-                HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME)) {
-            return;
-        }
         setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null,
                 callingPackage, attributionTag);
     }
@@ -5080,7 +5057,6 @@
     /** @see AudioManager#setMasterMute(boolean, int) */
     public void setMasterMute(boolean mute, int flags, String callingPackage, int userId,
             String attributionTag) {
-
         super.setMasterMute_enforcePermission();
 
         setMasterMuteInternal(mute, flags, callingPackage,
@@ -5446,10 +5422,6 @@
     }
 
     public void setRingerModeExternal(int ringerMode, String caller) {
-        if (mHardeningEnforcer.blockVolumeMethod(
-                HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_RINGER_MODE)) {
-            return;
-        }
         if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
                 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
             throw new SecurityException("Not allowed to change Do Not Disturb state");
@@ -6202,35 +6174,6 @@
                 AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
     }
 
-    /**
-      * @see AudioManager#adjustVolume(int, int)
-      * This method is redirected from AudioManager to AudioService for API hardening rules
-      * enforcement then to MediaSession for implementation.
-      */
-    @Override
-    public void adjustVolume(int direction, int flags) {
-        if (mHardeningEnforcer.blockVolumeMethod(
-                HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_VOLUME)) {
-            return;
-        }
-        getMediaSessionManager().dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                    direction, flags);
-    }
-
-    /**
-     * @see AudioManager#adjustSuggestedStreamVolume(int, int, int)
-     * This method is redirected from AudioManager to AudioService for API hardening rules
-     * enforcement then to MediaSession for implementation.
-     */
-    @Override
-    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
-        if (mHardeningEnforcer.blockVolumeMethod(
-                HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME)) {
-            return;
-        }
-        getMediaSessionManager().dispatchAdjustVolume(suggestedStreamType, direction, flags);
-    }
-
     /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */
     @Override
     public void setStreamVolumeForUid(int streamType, int index, int flags,
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
deleted file mode 100644
index 4ceb83b2..0000000
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.audio;
-
-import static android.media.audio.Flags.autoPublicVolumeApiHardening;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.media.AudioManager;
-import android.os.Binder;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-/**
- * Class to encapsulate all audio API hardening operations
- */
-public class HardeningEnforcer {
-
-    private static final String TAG = "AS.HardeningEnforcer";
-
-    final Context mContext;
-    final boolean mIsAutomotive;
-
-    /**
-     * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)}
-     */
-    public static final int METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME = 100;
-    /**
-     * Matches calls from {@link AudioManager#adjustVolume(int, int)}
-     */
-    public static final int METHOD_AUDIO_MANAGER_ADJUST_VOLUME = 101;
-    /**
-     * Matches calls from {@link AudioManager#adjustSuggestedStreamVolume(int, int, int)}
-     */
-    public static final int METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME = 102;
-    /**
-     * Matches calls from {@link AudioManager#adjustStreamVolume(int, int, int)}
-     */
-    public static final int METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME = 103;
-    /**
-     * Matches calls from {@link AudioManager#setRingerMode(int)}
-     */
-    public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200;
-
-    public HardeningEnforcer(Context ctxt, boolean isAutomotive) {
-        mContext = ctxt;
-        mIsAutomotive = isAutomotive;
-    }
-
-    /**
-     * Checks whether the call in the current thread should be allowed or blocked
-     * @param volumeMethod name of the method to check, for logging purposes
-     * @return false if the method call is allowed, true if it should be a no-op
-     */
-    protected boolean blockVolumeMethod(int volumeMethod) {
-        // for Auto, volume methods require MODIFY_AUDIO_SETTINGS_PRIVILEGED
-        if (mIsAutomotive) {
-            if (!autoPublicVolumeApiHardening()) {
-                // automotive hardening flag disabled, no blocking on auto
-                return false;
-            }
-            if (mContext.checkCallingOrSelfPermission(
-                    Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
-                    == PackageManager.PERMISSION_GRANTED) {
-                return false;
-            }
-            if (Binder.getCallingUid() < UserHandle.AID_APP_START) {
-                return false;
-            }
-            // TODO metrics?
-            // TODO log for audio dumpsys?
-            Log.e(TAG, "Preventing volume method " + volumeMethod + " for "
-                    + getPackNameForUid(Binder.getCallingUid()));
-            return true;
-        }
-        // not blocking
-        return false;
-    }
-
-    private String getPackNameForUid(int uid) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            final String[] names = mContext.getPackageManager().getPackagesForUid(uid);
-            if (names == null
-                    || names.length == 0
-                    || TextUtils.isEmpty(names[0])) {
-                return "[" + uid + "]";
-            }
-            return names[0];
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c2a1b6b..0492f43 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -828,6 +828,22 @@
             }
         }
 
+        // Removes all notifications with the specified user & package.
+        public void removePackageNotifications(String pkg, @UserIdInt int userId) {
+            synchronized (mBufferLock) {
+                Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
+                while (bufferIter.hasNext()) {
+                    final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
+                    if (pair.first != null
+                            && userId == pair.first.getNormalizedUserId()
+                            && pkg != null && pkg.equals(pair.first.getPackageName())
+                            && pair.first.getNotification() != null) {
+                        bufferIter.remove();
+                    }
+                }
+            }
+        }
+
         void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
             synchronized (mBufferLock) {
                 Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
@@ -1902,7 +1918,6 @@
                         unhideNotificationsForPackages(pkgList, uidList);
                     }
                 }
-
                 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
             }
         }
@@ -4216,7 +4231,8 @@
             boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
                     pkg, callingUid, channelId, callingUid, isSystemOrSystemUi);
             if (previouslyExisted) {
-                // Remove from both recent notification archive and notification history
+                // Remove from both recent notification archive (recently dismissed notifications)
+                // and notification history
                 mArchive.removeChannelNotifications(pkg, callingUser, channelId);
                 mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
                 mListeners.notifyNotificationChannelChanged(pkg,
@@ -9418,7 +9434,11 @@
             for (int i = 0; i < size; i++) {
                 final String pkg = pkgList[i];
                 final int uid = uidList[i];
-                mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg);
+                final int userHandle = UserHandle.getUserId(uid);
+                // Removes this package's notifications from both recent notification archive
+                // (recently dismissed notifications) and notification history.
+                mArchive.removePackageNotifications(pkg, userHandle);
+                mHistoryManager.onPackageRemoved(userHandle, pkg);
             }
         }
         if (preferencesChanged) {
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 79cd2a0..92d469c 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -259,6 +259,19 @@
      */
     boolean shouldFilterApplicationIncludingUninstalled(@Nullable PackageStateInternal ps,
             int callingUid, int userId);
+
+    /**
+     * Different from
+     * {@link #shouldFilterApplicationIncludingUninstalled(PackageStateInternal, int, int)}, the
+     * function returns {@code true} if:
+     * <ul>
+     * <li>The target package is not archived.
+     * <li>The package cannot be found in the device or has been uninstalled in the current user.
+     * </ul>
+     */
+    boolean shouldFilterApplicationIncludingUninstalledNotArchived(
+            @Nullable PackageStateInternal ps,
+            int callingUid, int userId);
     /**
      * Different from {@link #shouldFilterApplication(SharedUserSetting, int, int)}, the function
      * returns {@code true} if packages with the same shared user are all uninstalled in the current
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 11a6d1b..e5c4ccc 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -2455,7 +2455,8 @@
      */
     public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
             int callingUid, @Nullable ComponentName component,
-            @PackageManager.ComponentType int componentType, int userId, boolean filterUninstall) {
+            @PackageManager.ComponentType int componentType, int userId, boolean filterUninstall,
+            boolean filterArchived) {
         if (Process.isSdkSandboxUid(callingUid)) {
             int clientAppUid = Process.getAppUidForSdkSandboxUid(callingUid);
             // SDK sandbox should be able to see it's client app
@@ -2469,14 +2470,20 @@
         }
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         final boolean callerIsInstantApp = instantAppPkgName != null;
+        final boolean packageArchivedForUser = ps != null && PackageArchiver.isArchived(
+                ps.getUserStateOrDefault(userId));
         // Don't treat hiddenUntilInstalled as an uninstalled state, phone app needs to access
         // these hidden application details to customize carrier apps. Also, allowing the system
         // caller accessing to application across users.
         if (ps == null
                 || (filterUninstall
-                        && !isSystemOrRootOrShell(callingUid)
-                        && !ps.isHiddenUntilInstalled()
-                        && !ps.getUserStateOrDefault(userId).isInstalled())) {
+                && !isSystemOrRootOrShell(callingUid)
+                && !ps.isHiddenUntilInstalled()
+                && !ps.getUserStateOrDefault(userId).isInstalled()
+                // Archived packages behave like uninstalled packages. So if filterUninstall is
+                // set to true, we dismiss filtering some uninstalled package only if it is
+                // archived and filterArchived is set as false.
+                && (!packageArchivedForUser || filterArchived))) {
             // If caller is instant app or sdk sandbox and ps is null, pretend the application
             // exists, but, needs to be filtered
             return (callerIsInstantApp || filterUninstall || Process.isSdkSandboxUid(callingUid));
@@ -2524,7 +2531,20 @@
     }
 
     /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
+     */
+    public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
+            int callingUid, @Nullable ComponentName component,
+            @PackageManager.ComponentType int componentType, int userId, boolean filterUninstall) {
+        return shouldFilterApplication(
+                ps, callingUid, component, componentType, userId, filterUninstall,
+                true /* filterArchived */);
+    }
+
+    /**
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
      */
     public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
             int callingUid, @Nullable ComponentName component,
@@ -2534,7 +2554,8 @@
     }
 
     /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
      */
     public final boolean shouldFilterApplication(
             @Nullable PackageStateInternal ps, int callingUid, int userId) {
@@ -2543,7 +2564,8 @@
     }
 
     /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
      */
     public final boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
             int callingUid, int userId) {
@@ -2558,7 +2580,8 @@
     }
 
     /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
      */
     public final boolean shouldFilterApplicationIncludingUninstalled(
             @Nullable PackageStateInternal ps, int callingUid, int userId) {
@@ -2567,7 +2590,19 @@
     }
 
     /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
+     */
+    public final boolean shouldFilterApplicationIncludingUninstalledNotArchived(
+            @Nullable PackageStateInternal ps, int callingUid, int userId) {
+        return shouldFilterApplication(
+                ps, callingUid, null, TYPE_UNKNOWN, userId, true /* filterUninstall */,
+                false /* filterArchived */);
+    }
+
+    /**
+     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean,
+     * boolean)
      */
     public final boolean shouldFilterApplicationIncludingUninstalled(
             @NonNull SharedUserSetting sus, int callingUid, int userId) {
@@ -5015,7 +5050,7 @@
         String installerPackageName = installSource.mInstallerPackageName;
         if (installerPackageName != null) {
             final PackageStateInternal ps = mSettings.getPackage(installerPackageName);
-            if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid,
+            if (ps == null || shouldFilterApplicationIncludingUninstalledNotArchived(ps, callingUid,
                     UserHandle.getUserId(callingUid))) {
                 installerPackageName = null;
             }
@@ -5033,7 +5068,8 @@
             return InstallSource.EMPTY;
         }
 
-        if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
+        if (ps == null || shouldFilterApplicationIncludingUninstalledNotArchived(ps, callingUid,
+                userId)) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 65c6329..3b3d79e 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -440,7 +440,7 @@
         if (outInfo != null) {
             // Remember which users are affected, before the installed states are modified
             outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
-                    ? ps.queryInstalledUsers(allUserHandles, /* installed= */true)
+                    ? ps.queryUsersInstalledOrHasData(allUserHandles)
                     : new int[]{userId};
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 72090f2..b50d0a0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -779,6 +779,10 @@
         return readUserState(userId).isInstalled();
     }
 
+    boolean isArchived(int userId) {
+        return PackageArchiver.isArchived(readUserState(userId));
+    }
+
     int getInstallReason(int userId) {
         return readUserState(userId).getInstallReason();
     }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index faccca8..315e7d8 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -55,6 +55,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
+import static com.android.window.flags.Flags.allowDisableActivityRecordInputSink;
 
 import android.Manifest;
 import android.annotation.ColorInt;
@@ -1688,4 +1689,20 @@
             return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken;
         }
     }
+
+    @Override
+    public void setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled) {
+        if (!allowDisableActivityRecordInputSink()) {
+            return;
+        }
+
+        mService.mAmInternal.enforceCallingPermission(
+                Manifest.permission.INTERNAL_SYSTEM_WINDOW, "setActivityRecordInputSinkEnabled");
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
+            if (r != null) {
+                r.mActivityRecordInputSinkEnabled = enabled;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 081759d..d90d4ff 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -970,6 +970,8 @@
     boolean mWaitForEnteringPinnedMode;
 
     final ActivityRecordInputSink mActivityRecordInputSink;
+    // System activities with INTERNAL_SYSTEM_WINDOW can disable ActivityRecordInputSink.
+    boolean mActivityRecordInputSinkEnabled = true;
 
     // Activities with this uid are allowed to not create an input sink while being in the same
     // task and directly above this ActivityRecord. This field is updated whenever a new activity
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index be7d9b6..c61d863 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -86,7 +86,8 @@
         final boolean allowPassthrough = activityBelowInTask != null && (
                 activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
                         || activityBelowInTask.isUid(mActivityRecord.getUid()));
-        if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
+        if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()
+                || !mActivityRecord.mActivityRecordInputSinkEnabled) {
             mInputWindowHandleWrapper.setInputConfigMasked(InputConfig.NOT_TOUCHABLE,
                     InputConfig.NOT_TOUCHABLE);
         } else {
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 0d196b4..7c53950 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -2175,9 +2175,9 @@
 
                     userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
                         _,
-                        deviceId,
+                        persistentDeviceId,
                         devicePermissionFlags ->
-                        println("Permissions (Device $deviceId):")
+                        println("Permissions (Device $persistentDeviceId):")
                         withIndent {
                             devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
                                 val isGranted = PermissionFlags.isPermissionGranted(flags)
@@ -2658,7 +2658,7 @@
         override fun onDevicePermissionFlagsChanged(
             appId: Int,
             userId: Int,
-            deviceId: String,
+            persistentDeviceId: String,
             permissionName: String,
             oldFlags: Int,
             newFlags: Int
@@ -2681,7 +2681,8 @@
                         permissionName in NOTIFICATIONS_PERMISSIONS &&
                             runtimePermissionRevokedUids.get(uid, true)
                 }
-                runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } += deviceId
+                runtimePermissionChangedUidDevices
+                    .getOrPut(uid) { mutableSetOf() } += persistentDeviceId
             }
 
             if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
@@ -2695,9 +2696,9 @@
                 isPermissionFlagsChanged = false
             }
 
-            runtimePermissionChangedUidDevices.forEachIndexed { _, uid, deviceIds ->
-                deviceIds.forEach { deviceId ->
-                    onPermissionsChangeListeners.onPermissionsChanged(uid, deviceId)
+            runtimePermissionChangedUidDevices.forEachIndexed { _, uid, persistentDeviceIds ->
+                persistentDeviceIds.forEach { persistentDeviceId ->
+                    onPermissionsChangeListeners.onPermissionsChanged(uid, persistentDeviceId)
                 }
             }
             runtimePermissionChangedUidDevices.clear()
@@ -2772,16 +2773,16 @@
             when (msg.what) {
                 MSG_ON_PERMISSIONS_CHANGED -> {
                     val uid = msg.arg1
-                    val deviceId = msg.obj as String
-                    handleOnPermissionsChanged(uid, deviceId)
+                    val persistentDeviceId = msg.obj as String
+                    handleOnPermissionsChanged(uid, persistentDeviceId)
                 }
             }
         }
 
-        private fun handleOnPermissionsChanged(uid: Int, deviceId: String) {
+        private fun handleOnPermissionsChanged(uid: Int, persistentDeviceId: String) {
             listeners.broadcast { listener ->
                 try {
-                    listener.onPermissionsChanged(uid, deviceId)
+                    listener.onPermissionsChanged(uid, persistentDeviceId)
                 } catch (e: RemoteException) {
                     Slog.e(LOG_TAG, "Error when calling OnPermissionsChangeListener", e)
                 }
@@ -2796,9 +2797,10 @@
             listeners.unregister(listener)
         }
 
-        fun onPermissionsChanged(uid: Int, deviceId: String) {
+        fun onPermissionsChanged(uid: Int, persistentDeviceId: String) {
             if (listeners.registeredCallbackCount > 0) {
-                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget()
+                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId)
+                    .sendToTarget()
             }
         }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 4b6183d..8bc027d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -31,6 +31,7 @@
 import android.app.Notification;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -39,6 +40,7 @@
 import com.android.server.UiServiceTestCase;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -55,6 +57,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ArchiveTest extends UiServiceTestCase {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private static final int SIZE = 5;
 
     private NotificationManagerService.Archive mArchive;
@@ -249,4 +254,29 @@
             assertThat(expected).contains(sbn.getKey());
         }
     }
+
+    @Test
+    public void testRemoveNotificationsByPackage() {
+        List<String> expected = new ArrayList<>();
+
+        StatusBarNotification sbn_remove = getNotification("pkg_remove", 0,
+                UserHandle.of(USER_CURRENT));
+        mArchive.record(sbn_remove, REASON_CANCEL);
+
+        StatusBarNotification sbn_keep = getNotification("pkg_keep", 1,
+                UserHandle.of(USER_CURRENT));
+        mArchive.record(sbn_keep, REASON_CANCEL);
+        expected.add(sbn_keep.getKey());
+
+        StatusBarNotification sbn_remove2 = getNotification("pkg_remove", 2,
+                UserHandle.of(USER_CURRENT));
+        mArchive.record(sbn_remove2, REASON_CANCEL);
+
+        mArchive.removePackageNotifications("pkg_remove", USER_CURRENT);
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
+        assertThat(actual).hasSize(expected.size());
+        for (StatusBarNotification sbn : actual) {
+            assertThat(expected).contains(sbn.getKey());
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a47fbce..b45dcd4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -65,6 +65,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Build.VERSION_CODES.O_MR1;
 import static android.os.Build.VERSION_CODES.P;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -72,7 +73,6 @@
 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
-import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
@@ -307,7 +307,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@@ -813,6 +812,20 @@
         mPackageIntentReceiver.onReceive(getContext(), intent);
     }
 
+    private void simulatePackageRemovedBroadcast(String pkg, int uid) {
+        // mimics receive broadcast that package is removed, but doesn't remove the package.
+        final Bundle extras = new Bundle();
+        extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+                new String[]{pkg});
+        extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
+
+        final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+        intent.setData(Uri.parse("package:" + pkg));
+        intent.putExtras(extras);
+
+        mPackageIntentReceiver.onReceive(getContext(), intent);
+    }
+
     private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
         // mimics receive broadcast that package is (un)distracting
         // but does not actually register that info with packagemanager
@@ -878,6 +891,22 @@
         mTestNotificationChannel.setAllowBubbles(channelEnabled);
     }
 
+    private void setUpPrefsForHistory(int uid, boolean globalEnabled) {
+        // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid);
+        // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0);
+
+        // Forces an update by calling observe on mSettingsObserver, which picks up the settings
+        // changes above.
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
+
+        assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, uid) != 0);
+    }
+
     private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
         Notification.Builder nb = new Notification.Builder(mContext, "a")
                 .setContentTitle("foo")
@@ -9831,6 +9860,43 @@
     }
 
     @Test
+    public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException {
+        // Enables Notification History setting
+        setUpPrefsForHistory(mUid, true /* =enabled */);
+
+        // Posts a notification to the mTestNotificationChannel.
+        final NotificationRecord notif = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, false);
+        mService.addNotification(notif);
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(
+                notif.getSbn().getPackageName());
+        assertEquals(1, notifs.length);
+
+        // Cancels all notifications.
+        mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0,
+                notif.getUserId(), REASON_CANCEL);
+        waitForIdle();
+        notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
+        assertEquals(0, notifs.length);
+
+        // Checks that notification history's recently canceled archive contains the notification.
+        notifs = mBinderService.getHistoricalNotificationsWithAttribution(PKG,
+                        mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
+        waitForIdle();
+        assertEquals(1, notifs.length);
+
+        // Remove sthe package that contained the channel
+        simulatePackageRemovedBroadcast(PKG, mUid);
+        waitForIdle();
+
+        // Checks that notification history no longer contains the notification.
+        notifs = mBinderService.getHistoricalNotificationsWithAttribution(
+                PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
+        waitForIdle();
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
     public void testNotificationHistory_addNoisyNotification() throws Exception {
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
                 null /* tvExtender */);
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 1b8d746..e83f03d 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -99,4 +99,7 @@
         enabled: false,
     },
 
+    data: [
+        ":OverlayTestApp",
+    ],
 }
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 762e23c..f2a1fe8 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -119,6 +119,9 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="com.android.server.wm.ActivityRecordInputSinkTests$TestActivity"
+                  android:exported="true">
+        </activity>
     </application>
 
     <instrumentation
diff --git a/services/tests/wmtests/AndroidTest.xml b/services/tests/wmtests/AndroidTest.xml
index 2717ef90..f8ebead 100644
--- a/services/tests/wmtests/AndroidTest.xml
+++ b/services/tests/wmtests/AndroidTest.xml
@@ -21,6 +21,7 @@
         <option name="cleanup-apks" value="true" />
         <option name="install-arg" value="-t" />
         <option name="test-file-name" value="WmTests.apk" />
+        <option name="test-file-name" value="OverlayTestApp.apk" />
     </target_preparer>
 
     <option name="test-tag" value="WmTests" />
diff --git a/services/tests/wmtests/OverlayApp/Android.bp b/services/tests/wmtests/OverlayApp/Android.bp
new file mode 100644
index 0000000..77d5b22
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/Android.bp
@@ -0,0 +1,19 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+    name: "OverlayTestApp",
+
+    srcs: ["**/*.java"],
+
+    resource_dirs: ["res"],
+
+    certificate: "platform",
+    platform_apis: true,
+}
diff --git a/services/tests/wmtests/OverlayApp/AndroidManifest.xml b/services/tests/wmtests/OverlayApp/AndroidManifest.xml
new file mode 100644
index 0000000..5b4ef57
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.server.wm.overlay_app">
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+
+    <application>
+        <activity android:name=".OverlayApp"
+                  android:exported="true"
+                  android:theme="@style/TranslucentFloatingTheme">
+        </activity>
+    </application>
+</manifest>
diff --git a/services/tests/wmtests/OverlayApp/res/values/styles.xml b/services/tests/wmtests/OverlayApp/res/values/styles.xml
new file mode 100644
index 0000000..fff10a3
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/res/values/styles.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="TranslucentFloatingTheme" >
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowNoTitle">true</item>
+
+        <!-- Disables starting window. -->
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+</resources>
diff --git a/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java b/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java
new file mode 100644
index 0000000..89161c5
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.overlay_app;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+/**
+ * Test app that is translucent not touchable modal.
+ * If launched with "disableInputSink" extra boolean value, this activity disables
+ * ActivityRecordInputSinkEnabled as long as the permission is granted.
+ */
+public class OverlayApp extends Activity {
+    private static final String KEY_DISABLE_INPUT_SINK = "disableInputSink";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout tv = new LinearLayout(this);
+        tv.setBackgroundColor(Color.GREEN);
+        tv.setPadding(50, 50, 50, 50);
+        tv.setGravity(Gravity.CENTER);
+        setContentView(tv);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+        if (getIntent().getBooleanExtra(KEY_DISABLE_INPUT_SINK, false)) {
+            setActivityRecordInputSinkEnabled(false);
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java
new file mode 100644
index 0000000..3b280d9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.window.WindowInfosListenerForTest;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.window.flags.Flags;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Internal variant of {@link android.server.wm.window.ActivityRecordInputSinkTests}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityRecordInputSinkTests {
+    private static final String OVERLAY_APP_PKG = "com.android.server.wm.overlay_app";
+    private static final String OVERLAY_ACTIVITY = OVERLAY_APP_PKG + "/.OverlayApp";
+    private static final String KEY_DISABLE_INPUT_SINK = "disableInputSink";
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Rule
+    public final ActivityScenarioRule<TestActivity> mActivityRule =
+            new ActivityScenarioRule<>(TestActivity.class);
+
+    private UiAutomation mUiAutomation;
+
+    @Before
+    public void setUp() {
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+    }
+
+    @After
+    public void tearDown() {
+        ActivityManager am =
+                InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
+                        ActivityManager.class);
+        mUiAutomation.adoptShellPermissionIdentity();
+        try {
+            am.forceStopPackage(OVERLAY_APP_PKG);
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    @Test
+    public void testSimpleButtonPress() {
+        injectTapOnButton();
+
+        mActivityRule.getScenario().onActivity(a -> {
+            assertEquals(1, a.mNumClicked);
+        });
+    }
+
+    @Test
+    public void testSimpleButtonPress_withOverlay() throws InterruptedException {
+        startOverlayApp(false);
+        waitForOverlayApp();
+
+        injectTapOnButton();
+
+        mActivityRule.getScenario().onActivity(a -> {
+            assertEquals(0, a.mNumClicked);
+        });
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ALLOW_DISABLE_ACTIVITY_RECORD_INPUT_SINK)
+    public void testSimpleButtonPress_withOverlayDisableInputSink() throws InterruptedException {
+        startOverlayApp(true);
+        waitForOverlayApp();
+
+        injectTapOnButton();
+
+        mActivityRule.getScenario().onActivity(a -> {
+            assertEquals(1, a.mNumClicked);
+        });
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ALLOW_DISABLE_ACTIVITY_RECORD_INPUT_SINK)
+    public void testSimpleButtonPress_withOverlayDisableInputSink_flagDisabled()
+            throws InterruptedException {
+        startOverlayApp(true);
+        waitForOverlayApp();
+
+        injectTapOnButton();
+
+        mActivityRule.getScenario().onActivity(a -> {
+            assertEquals(0, a.mNumClicked);
+        });
+    }
+
+    private void startOverlayApp(boolean disableInputSink) {
+        String launchCommand = "am start -n " + OVERLAY_ACTIVITY;
+        if (disableInputSink) {
+            launchCommand += " --ez " + KEY_DISABLE_INPUT_SINK + " true";
+        }
+
+        mUiAutomation.adoptShellPermissionIdentity();
+        try {
+            mUiAutomation.executeShellCommand(launchCommand);
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    private void waitForOverlayApp() throws InterruptedException {
+        final var listenerHost = new WindowInfosListenerForTest();
+        final var latch = new CountDownLatch(1);
+        final Consumer<List<WindowInfosListenerForTest.WindowInfo>> listener = windowInfos -> {
+            final boolean inputSinkReady = windowInfos.stream().anyMatch(info ->
+                    info.isVisible
+                            && info.name.contains("ActivityRecordInputSink " + OVERLAY_ACTIVITY));
+            if (inputSinkReady) {
+                latch.countDown();
+            }
+        };
+
+        listenerHost.addWindowInfosListener(listener);
+        try {
+            assertTrue(latch.await(5, TimeUnit.SECONDS));
+        } finally {
+            listenerHost.removeWindowInfosListener(listener);
+        }
+    }
+
+    private void injectTapOnButton() {
+        Rect buttonBounds = new Rect();
+        mActivityRule.getScenario().onActivity(a -> {
+            a.mButton.getBoundsOnScreen(buttonBounds);
+        });
+        final int x = buttonBounds.centerX();
+        final int y = buttonBounds.centerY();
+
+        MotionEvent down = MotionEvent.obtain(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0);
+        mUiAutomation.injectInputEvent(down, true);
+
+        SystemClock.sleep(10);
+
+        MotionEvent up = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+                MotionEvent.ACTION_UP, x, y, 0);
+        mUiAutomation.injectInputEvent(up, true);
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    public static class TestActivity extends Activity {
+        int mNumClicked = 0;
+        Button mButton;
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mButton = new Button(this);
+            mButton.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT));
+            setContentView(mButton);
+            mButton.setOnClickListener(v -> mNumClicked++);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
index 4a3a798..668c94c 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -27,9 +27,10 @@
 
 /**
  * Tentative, partial implementation of the Parcel native methods, using Java's
- * {@link ByteBuffer}. It turned out there's enough semantics differences between Parcel
- * and {@link ByteBuffer}, so it didn't actually work.
- * (e.g. Parcel seems to allow moving the data position to be beyond its size? Which
+ * {@code byte[]}.
+ * (We don't use a {@link ByteBuffer} because there's enough semantics differences between Parcel
+ * and {@link ByteBuffer}, and it didn't work out.
+ * e.g. Parcel seems to allow moving the data position to be beyond its size? Which
  * {@link ByteBuffer} wouldn't allow...)
  */
 public class Parcel_host {
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
index 89daa20..85038be 100755
--- a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
+++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# This command is expected to be executed with: atest hoststubgen-invoke-test
+
 set -e # Exit when any command files
 
 # This script runs HostStubGen directly with various arguments and make sure
@@ -35,6 +37,12 @@
   mkdir -p $TEMP
 fi
 
+cleanup_temp() {
+  rm -fr $TEMP/*
+}
+
+cleanup_temp
+
 JAR=hoststubgen-test-tiny-framework.jar
 STUB=$TEMP/stub.jar
 IMPL=$TEMP/impl.jar
@@ -47,12 +55,10 @@
 # HostStubGen result in it.
 HOSTSTUBGEN_RC=0
 
-# Define the functions to
-
-
 # Note, because the build rule will only install hoststubgen.jar, but not the wrapper script,
 # we need to execute it manually with the java command.
 hoststubgen() {
+  echo "Running hoststubgen with: $*"
   java -jar ./hoststubgen.jar "$@"
 }
 
@@ -62,7 +68,7 @@
 
   echo "# Test: $test_name"
 
-  rm -f $HOSTSTUBGEN_OUT
+  cleanup_temp
 
   local filter_arg=""
 
@@ -73,11 +79,21 @@
     cat $ANNOTATION_FILTER
   fi
 
+  local stub_arg=""
+  local impl_arg=""
+
+  if [[ "$STUB" != "" ]] ; then
+    stub_arg="--out-stub-jar $STUB"
+  fi
+  if [[ "$IMPL" != "" ]] ; then
+    impl_arg="--out-impl-jar $IMPL"
+  fi
+
   hoststubgen \
       --debug \
       --in-jar $JAR \
-      --out-stub-jar $STUB \
-      --out-impl-jar $IMPL \
+      $stub_arg \
+      $impl_arg \
       --stub-annotation \
           android.hosttest.annotation.HostSideTestStub \
       --keep-annotation \
@@ -105,6 +121,21 @@
   return 0
 }
 
+assert_file_generated() {
+  local file="$1"
+  if [[ "$file" == "" ]] ; then
+    if [[ -f "$file" ]] ; then
+      echo "HostStubGen shouldn't have generated $file"
+      return 1
+    fi
+  else
+    if ! [[ -f "$file" ]] ; then
+      echo "HostStubGen didn't generate $file"
+      return 1
+    fi
+  fi
+}
+
 run_hoststubgen_for_success() {
   run_hoststubgen "$@"
 
@@ -112,6 +143,9 @@
     echo "HostStubGen expected to finish successfully, but failed with $rc"
     return 1
   fi
+
+  assert_file_generated "$STUB"
+  assert_file_generated "$IMPL"
 }
 
 run_hoststubgen_for_failure() {
@@ -189,6 +223,11 @@
 * # All other classes allowed
 "
 
+STUB="" run_hoststubgen_for_success "No stub generation" ""
+
+IMPL="" run_hoststubgen_for_success "No impl generation" ""
+
+STUB="" IMPL="" run_hoststubgen_for_success "No stub, no impl generation" ""
 
 
 echo "All tests passed"
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 07bd2dc..3cdddc2 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -237,8 +237,8 @@
      */
     private fun convert(
             inJar: String,
-            outStubJar: String,
-            outImplJar: String,
+            outStubJar: String?,
+            outImplJar: String?,
             filter: OutputFilter,
             enableChecker: Boolean,
             classes: ClassNodes,
@@ -254,8 +254,8 @@
         log.withIndent {
             // Open the input jar file and process each entry.
             ZipFile(inJar).use { inZip ->
-                ZipOutputStream(FileOutputStream(outStubJar)).use { stubOutStream ->
-                    ZipOutputStream(FileOutputStream(outImplJar)).use { implOutStream ->
+                maybeWithZipOutputStream(outStubJar) { stubOutStream ->
+                    maybeWithZipOutputStream(outImplJar) { implOutStream ->
                         val inEntries = inZip.entries()
                         while (inEntries.hasMoreElements()) {
                             val entry = inEntries.nextElement()
@@ -265,22 +265,29 @@
                         log.i("Converted all entries.")
                     }
                 }
-                log.i("Created stub: $outStubJar")
-                log.i("Created impl: $outImplJar")
+                outStubJar?.let { log.i("Created stub: $it") }
+                outImplJar?.let { log.i("Created impl: $it") }
             }
         }
         val end = System.currentTimeMillis()
         log.v("Done transforming the jar in %.1f second(s).", (end - start) / 1000.0)
     }
 
+    private fun <T> maybeWithZipOutputStream(filename: String?, block: (ZipOutputStream?) -> T): T {
+        if (filename == null) {
+            return block(null)
+        }
+        return ZipOutputStream(FileOutputStream(filename)).use(block)
+    }
+
     /**
      * Convert a single ZIP entry, which may or may not be a class file.
      */
     private fun convertSingleEntry(
             inZip: ZipFile,
             entry: ZipEntry,
-            stubOutStream: ZipOutputStream,
-            implOutStream: ZipOutputStream,
+            stubOutStream: ZipOutputStream?,
+            implOutStream: ZipOutputStream?,
             filter: OutputFilter,
             packageRedirector: PackageRedirectRemapper,
             enableChecker: Boolean,
@@ -316,8 +323,8 @@
             // Unknown type, we just copy it to both output zip files.
             // TODO: We probably shouldn't do it for stub jar?
             log.v("Copying: %s", entry.name)
-            copyZipEntry(inZip, entry, stubOutStream)
-            copyZipEntry(inZip, entry, implOutStream)
+            stubOutStream?.let { copyZipEntry(inZip, entry, it) }
+            implOutStream?.let { copyZipEntry(inZip, entry, it) }
         }
     }
 
@@ -346,8 +353,8 @@
     private fun processSingleClass(
             inZip: ZipFile,
             entry: ZipEntry,
-            stubOutStream: ZipOutputStream,
-            implOutStream: ZipOutputStream,
+            stubOutStream: ZipOutputStream?,
+            implOutStream: ZipOutputStream?,
             filter: OutputFilter,
             packageRedirector: PackageRedirectRemapper,
             enableChecker: Boolean,
@@ -361,7 +368,7 @@
             return
         }
         // Generate stub first.
-        if (classPolicy.policy.needsInStub) {
+        if (stubOutStream != null && classPolicy.policy.needsInStub) {
             log.v("Creating stub class: %s Policy: %s", classInternalName, classPolicy)
             log.withIndent {
                 BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
@@ -374,8 +381,8 @@
                 }
             }
         }
-        log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy)
-        if (classPolicy.policy.needsInImpl) {
+        if (implOutStream != null && classPolicy.policy.needsInImpl) {
+            log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy)
             log.withIndent {
                 BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
                     val newEntry = ZipEntry(entry.name)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index da53487..83f873d 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -28,10 +28,10 @@
         var inJar: String = "",
 
         /** Output stub jar file */
-        var outStubJar: String = "",
+        var outStubJar: String? = null,
 
         /** Output implementation jar file */
-        var outImplJar: String = "",
+        var outImplJar: String? = null,
 
         var inputJarDumpFile: String? = null,
 
@@ -71,7 +71,7 @@
         var enablePreTrace: Boolean = false,
         var enablePostTrace: Boolean = false,
 
-        var enableNonStubMethodCallDetection: Boolean = true,
+        var enableNonStubMethodCallDetection: Boolean = false,
 ) {
     companion object {
 
@@ -209,11 +209,14 @@
             if (ret.inJar.isEmpty()) {
                 throw ArgumentsException("Required option missing: --in-jar")
             }
-            if (ret.outStubJar.isEmpty()) {
-                throw ArgumentsException("Required option missing: --out-stub-jar")
+            if (ret.outStubJar == null && ret.outImplJar == null) {
+                log.w("Neither --out-stub-jar nor --out-impl-jar is set." +
+                        " $COMMAND_NAME will not generate jar files.")
             }
-            if (ret.outImplJar.isEmpty()) {
-                throw ArgumentsException("Required option missing: --out-impl-jar")
+
+            if (ret.enableNonStubMethodCallDetection) {
+                log.w("--enable-non-stub-method-check is not fully implemented yet." +
+                    " See the todo in doesMethodNeedNonStubCallCheck().")
             }
 
             return ret
diff --git a/tools/hoststubgen/hoststubgen/test-framework/README.md b/tools/hoststubgen/hoststubgen/test-framework/README.md
index 20e2f87..f616ad6 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/README.md
+++ b/tools/hoststubgen/hoststubgen/test-framework/README.md
@@ -14,12 +14,6 @@
 $ atest --no-bazel-mode HostStubGenTest-framework-test-host-test
 ```
 
-- With `run-ravenwood-test`
-
-```
-$ run-ravenwood-test HostStubGenTest-framework-test-host-test
-```
-
 - Advanced option: `run-test-without-atest.sh` runs the test without using `atest` or `run-ravenwood-test`
 
 ```
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
index f3c0450..3bfad9b 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
@@ -13,12 +13,6 @@
 $ atest hoststubgen-test-tiny-test
 ```
 
-- With `run-ravenwood-test` should work too. This is the proper way to run it.
-
-```
-$ run-ravenwood-test hoststubgen-test-tiny-test
-```
-
 - `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
   using the build system. This is useful for debugging the tool.
 
diff --git a/tools/hoststubgen/scripts/Android.bp b/tools/hoststubgen/scripts/Android.bp
index 5da805e..b1ba07e 100644
--- a/tools/hoststubgen/scripts/Android.bp
+++ b/tools/hoststubgen/scripts/Android.bp
@@ -18,9 +18,3 @@
     tools: ["dump-jar"],
     cmd: "$(location dump-jar) -s -o $(out) $(in)",
 }
-
-sh_binary_host {
-    name: "run-ravenwood-test",
-    src: "run-ravenwood-test",
-    visibility: ["//visibility:public"],
-}
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index 2dac089..82faa91 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -22,10 +22,10 @@
 READY_TEST_MODULES=(
   HostStubGenTest-framework-all-test-host-test
   hoststubgen-test-tiny-test
+  CtsUtilTestCasesRavenwood
 )
 
 MUST_BUILD_MODULES=(
-    run-ravenwood-test
     "${NOT_READY_TEST_MODULES[*]}"
     HostStubGenTest-framework-test
 )
@@ -51,8 +51,6 @@
 # run ./scripts/build-framework-hostside-jars-without-genrules.sh
 
 # These tests should all pass.
-run-ravenwood-test ${READY_TEST_MODULES[*]}
-
-run atest CtsUtilTestCasesRavenwood
+run atest ${READY_TEST_MODULES[*]}
 
 echo ""${0##*/}" finished, with no unexpected failures. Ready to submit!"
\ No newline at end of file
diff --git a/tools/hoststubgen/scripts/run-ravenwood-test b/tools/hoststubgen/scripts/run-ravenwood-test
deleted file mode 100755
index 9bbb859..0000000
--- a/tools/hoststubgen/scripts/run-ravenwood-test
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -e
-
-# Script to run a "Ravenwood" host side test.
-#
-# A proper way to run these tests is to use `atest`, but `atest` has a known issue of loading
-# unrelated jar files as the class path, so for now we use this script to run host side tests.
-
-# Copy (with some changes) some functions from ../common.sh, so this script can be used without it.
-
-m() {
-  if (( $SKIP_BUILD )) ; then
-    echo "Skipping build: $*" 1>&2
-    return 0
-  fi
-  run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
-}
-
-run() {
-  echo "Running: $*" 1>&2
-  "$@"
-}
-
-run_junit_test_jar() {
-  local jar="$1"
-  echo "Starting test: $jar ..."
-  run cd "${jar%/*}"
-
-  run ${JAVA:-java} $JAVA_OPTS \
-      -cp $jar \
-      org.junit.runner.JUnitCore \
-      com.android.hoststubgen.hosthelper.HostTestSuite || return 1
-  return 0
-}
-
-help() {
-  cat <<'EOF'
-
-  run-ravenwood-test -- Run Ravenwood host tests
-
-  Usage:
-    run-ravenwood-test [options] MODULE-NAME ...
-
-  Options:
-    -h: Help
-    -t: Run test only, without building
-    -b: Build only, without running
-
-  Example:
-    run-ravenwood-test HostStubGenTest-framework-test-host-test
-
-EOF
-}
-
-#-------------------------------------------------------------------------
-# Parse options
-#-------------------------------------------------------------------------
-build=0
-test=0
-
-while getopts "htb" opt; do
-  case "$opt" in
-    h) help; exit 0 ;;
-    t)
-      test=1
-      ;;
-    b)
-      build=1
-      ;;
-  esac
-done
-shift $(($OPTIND - 1))
-
-# If neither -t nor -b is provided, then build and run./
-if (( ( $build + $test ) == 0 )) ; then
-  build=1
-  test=1
-fi
-
-
-modules=("${@}")
-
-if (( "${#modules[@]}" == 0 )); then
-  help
-  exit 1
-fi
-
-#-------------------------------------------------------------------------
-# Build
-#-------------------------------------------------------------------------
-if (( $build )) ; then
-  run m "${modules[@]}"
-fi
-
-#-------------------------------------------------------------------------
-# Run
-#-------------------------------------------------------------------------
-
-failures=0
-if (( test )) ; then
-  for module in "${modules[@]}"; do
-    if run_junit_test_jar "$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/${module}/${module}.jar"; then
-      : # passed.
-    else
-      failures=$(( failures + 1 ))
-    fi
-  done
-
-  if (( $failures > 0 )) ; then
-    echo "$failures test jar(s) failed." 1>&2
-    exit 2
-  fi
-fi
-
-exit 0
\ No newline at end of file