Merge "Allow DISALLOW_CONFIG_DEFAULT_APPS to apply on the personal profile" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2babf6a..6337022 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -93,16 +93,33 @@
     ],
 }
 
+// Jars in "ravenwood-runtime" are set to the classpath, sorted alphabetically.
+// Rename some of the dependencies to make sure they're included in the intended order.
+java_genrule {
+    name: "100-framework-minus-apex.ravenwood",
+    cmd: "cp $(in) $(out)",
+    srcs: [":framework-minus-apex.ravenwood"],
+    out: ["100-framework-minus-apex.ravenwood.jar"],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule {
+    // Use 200 to make sure it comes before the mainline stub ("all-updatable...").
+    name: "200-kxml2-android",
+    cmd: "cp $(in) $(out)",
+    srcs: [":kxml2-android"],
+    out: ["200-kxml2-android.jar"],
+    visibility: ["//visibility:private"],
+}
+
 android_ravenwood_libgroup {
     name: "ravenwood-runtime",
     libs: [
-        // Prefixed with "200" to ensure it's sorted early in Tradefed classpath
-        // so that we provide a concrete implementation before Mainline stubs
+        "100-framework-minus-apex.ravenwood",
         "200-kxml2-android",
         "all-updatable-modules-system-stubs",
         "android.test.mock.ravenwood",
-        "framework-minus-apex.ravenwood",
-        "hoststubgen-helper-framework-runtime.ravenwood",
+        "ravenwood-helper-runtime",
         "hoststubgen-helper-runtime.ravenwood",
 
         // Provide runtime versions of utils linked in below
diff --git a/core/api/current.txt b/core/api/current.txt
index db7334e2..2d03be7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7955,9 +7955,11 @@
     field public static final String LOCK_TASK_POLICY = "lockTask";
     field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
     field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+    field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
     field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
     field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
     field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+    field @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") public static final String SECURITY_LOGGING_POLICY = "securityLogging";
     field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
     field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
     field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
@@ -22496,6 +22498,7 @@
     method @NonNull public static android.view.Surface createPersistentInputSurface();
     method public int dequeueInputBuffer(long);
     method public int dequeueOutputBuffer(@NonNull android.media.MediaCodec.BufferInfo, long);
+    method @FlaggedApi("android.media.codec.null_output_surface") public void detachOutputSurface();
     method protected void finalize();
     method public void flush();
     method @NonNull public String getCanonicalName();
@@ -22519,6 +22522,7 @@
     method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
     method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueSecureInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
     method public void release();
     method public void releaseOutputBuffer(int, boolean);
     method public void releaseOutputBuffer(int, long);
@@ -22543,6 +22547,7 @@
     field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
     field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
     field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
+    field @FlaggedApi("android.media.codec.null_output_surface") public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8; // 0x8
     field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
     field public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2; // 0x2
     field public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4; // 0x4
@@ -22694,6 +22699,7 @@
     method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
     method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
     method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
     method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
     method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
   }
@@ -22788,6 +22794,7 @@
     field @Deprecated public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field @FlaggedApi("android.media.codec.null_output_surface") public static final String FEATURE_DetachedSurface = "detached-surface";
     field @FlaggedApi("android.media.codec.dynamic_color_aspects") public static final String FEATURE_DynamicColorAspects = "dynamic-color-aspects";
     field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
     field public static final String FEATURE_EncodingStatistics = "encoding-statistics";
@@ -39648,7 +39655,7 @@
     method @Nullable public java.util.Date getKeyValidityStart();
     method @NonNull public String getKeystoreAlias();
     method public int getMaxUsageCount();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
@@ -39656,7 +39663,7 @@
     method public boolean isDevicePropertiesAttestationIncluded();
     method @NonNull public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isStrongBoxBacked();
     method public boolean isUnlockedDeviceRequired();
@@ -39688,7 +39695,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -39793,14 +39800,14 @@
     method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
     method @Nullable public java.util.Date getKeyValidityStart();
     method public int getMaxUsageCount();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
@@ -39822,7 +39829,7 @@
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
@@ -50509,7 +50516,7 @@
     method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
     method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
     method public default int getBufferTransformHint();
-    method @FlaggedApi("com.android.window.flags.get_host_token_api") @Nullable public default android.os.IBinder getHostToken();
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken();
     method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
     method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
     method public default void setTouchableRegion(@Nullable android.graphics.Region);
@@ -52219,6 +52226,7 @@
 
   public class SurfaceControlViewHost {
     ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
+    ctor @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.window.InputTransferToken);
     method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
     method @Nullable public android.view.View getView();
     method public void relayout(int, int);
@@ -52420,7 +52428,7 @@
     method public final void cancelPendingInputEvents();
     method public boolean checkInputConnectionProxy(android.view.View);
     method public void clearAnimation();
-    method @FlaggedApi("autofill_credman_dev_integration") public void clearCredentialManagerRequest();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void clearCredentialManagerRequest();
     method public void clearFocus();
     method public void clearViewTranslationCallback();
     method public static int combineMeasuredStates(int, int);
@@ -52530,8 +52538,8 @@
     method @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") public final int getContentSensitivity();
     method @UiContext public final android.content.Context getContext();
     method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
-    method @FlaggedApi("autofill_credman_dev_integration") @Nullable public final android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
-    method @FlaggedApi("autofill_credman_dev_integration") @Nullable public final android.credentials.GetCredentialRequest getCredentialManagerRequest();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public final android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public final android.credentials.GetCredentialRequest getCredentialManagerRequest();
     method public final boolean getDefaultFocusHighlightEnabled();
     method public static int getDefaultSize(int, int);
     method public android.view.Display getDisplay();
@@ -52916,7 +52924,7 @@
     method public void setContentDescription(CharSequence);
     method @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") public final void setContentSensitivity(int);
     method public void setContextClickable(boolean);
-    method @FlaggedApi("autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
     method public void setDefaultFocusHighlightEnabled(boolean);
     method @Deprecated public void setDrawingCacheBackgroundColor(@ColorInt int);
     method @Deprecated public void setDrawingCacheEnabled(boolean);
@@ -53795,11 +53803,11 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method @FlaggedApi("autofill_credman_dev_integration") public void clearCredentialManagerRequest();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void clearCredentialManagerRequest();
     method @Nullable public abstract android.view.autofill.AutofillId getAutofillId();
     method public abstract int getChildCount();
-    method @FlaggedApi("autofill_credman_dev_integration") @Nullable public android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
-    method @FlaggedApi("autofill_credman_dev_integration") @Nullable public android.credentials.GetCredentialRequest getCredentialManagerRequest();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException> getCredentialManagerCallback();
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") @Nullable public android.credentials.GetCredentialRequest getCredentialManagerRequest();
     method public abstract android.os.Bundle getExtras();
     method public abstract CharSequence getHint();
     method public abstract CharSequence getText();
@@ -53824,7 +53832,7 @@
     method public abstract void setClickable(boolean);
     method public abstract void setContentDescription(CharSequence);
     method public abstract void setContextClickable(boolean);
-    method @FlaggedApi("autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
+    method @FlaggedApi("android.service.autofill.autofill_credman_dev_integration") public void setCredentialManagerRequest(@NonNull android.credentials.GetCredentialRequest, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.GetCredentialException>);
     method public abstract void setDataIsSensitive(boolean);
     method public abstract void setDimens(int, int, int, int, int, int);
     method public abstract void setElevation(float);
@@ -54365,9 +54373,9 @@
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
     method public default boolean isCrossWindowBlurEnabled();
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
     method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
     method @FlaggedApi("com.android.window.flags.screen_recording_callbacks") @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_RECORDING) public default void removeScreenRecordingCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -61348,6 +61356,12 @@
     field public static final int EDGE_RIGHT = 1; // 0x1
   }
 
+  @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public final class InputTransferToken implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.window.InputTransferToken> CREATOR;
+  }
+
   public interface OnBackAnimationCallback extends android.window.OnBackInvokedCallback {
     method public default void onBackCancelled();
     method public default void onBackProgressed(@NonNull android.window.BackEvent);
@@ -61395,11 +61409,11 @@
   @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public final class TrustedPresentationThresholds implements android.os.Parcelable {
     ctor @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public int describeContents();
+    method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public float getMinAlpha();
+    method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public float getMinFractionRendered();
+    method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @IntRange(from=1) public int getStabilityRequirementMillis();
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public void writeToParcel(@NonNull android.os.Parcel, int);
     field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @NonNull public static final android.os.Parcelable.Creator<android.window.TrustedPresentationThresholds> CREATOR;
-    field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minAlpha;
-    field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) public final float minFractionRendered;
-    field @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") @IntRange(from=1) public final int stabilityRequirementMs;
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 88f9aff..159410d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1307,6 +1307,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.app.admin.DevicePolicyState getDevicePolicyState();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public String getFinancedDeviceKioskRoleHolder();
+    method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getMaxPolicyStorageLimit();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public java.util.List<android.os.UserHandle> getPolicyManagedProfiles(@NonNull android.os.UserHandle);
@@ -1329,6 +1330,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public void setApplicationExemptions(@NonNull String, @NonNull java.util.Set<java.lang.Integer>) throws android.content.pm.PackageManager.NameNotFoundException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
+    method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
     method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
@@ -3191,6 +3193,8 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideWearableConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_data_request_observer_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void registerDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void startHotwordRecognition(@Nullable android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void stopHotwordRecognition(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("android.app.wearable.enable_data_request_observer_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void unregisterDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     field public static final int STATUS_ACCESS_DENIED = 5; // 0x5
     field @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") public static final int STATUS_CHANNEL_ERROR = 7; // 0x7
@@ -10430,9 +10434,11 @@
     method public int getFlags();
     method public int getMode();
     field public static final int BUGREPORT_FLAG_DEFER_CONSENT = 2; // 0x2
+    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
     field public static final int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 1; // 0x1
     field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
     field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
+    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
     field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
     field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
     field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
@@ -13188,6 +13194,7 @@
     method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult();
     method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras();
     method @Deprecated @Nullable public byte[] getTriggerAudio();
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") public boolean isRecognitionStopped();
     field public static final int DATA_FORMAT_RAW = 0; // 0x0
     field public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; // 0x1
   }
@@ -13294,6 +13301,7 @@
     method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer);
     field @Deprecated public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0
     field @Deprecated public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64
+    field @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") public static final String KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK = "android.service.voice.HotwordDetectionService.KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK";
     field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
   }
 
@@ -13578,7 +13586,11 @@
     method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
     method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @BinderThread public void onSecureWearableConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStartHotwordRecognition(@NonNull java.util.function.Consumer<android.service.voice.HotwordAudioStream>, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method public abstract void onStopDetection(@NonNull String);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStopHotwordAudioStream();
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStopHotwordRecognition(@NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onValidatedByHotwordDetectionService();
     field public static final String SERVICE_INTERFACE = "android.service.wearable.WearableSensingService";
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index cd84c84..3838b94 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2277,9 +2277,7 @@
   }
 
   public final class BugreportParams {
-    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
     field @FlaggedApi("android.os.bugreport_mode_max_value") public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
-    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
   }
 
   public class Build {
@@ -3172,6 +3170,7 @@
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHalEventReceivedMillis(long);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult);
+    method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setIsRecognitionStopped(boolean);
     method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
   }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ab9a4ec..23fe731 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3927,6 +3927,7 @@
 
         if (keyCode == KeyEvent.KEYCODE_ESCAPE && mWindow.shouldCloseOnTouchOutside()) {
             event.startTracking();
+            finish();
             return true;
         }
 
@@ -4027,10 +4028,7 @@
         }
 
         if (keyCode == KeyEvent.KEYCODE_ESCAPE
-                && mWindow.shouldCloseOnTouchOutside()
-                && event.isTracking()
-                && !event.isCanceled()) {
-            finish();
+                && event.isTracking()) {
             return true;
         }
 
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index d0d76a4..0e20138 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -672,7 +672,16 @@
      */
     @Override
     public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            event.startTracking();
+            return true;
+        }
+        if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+            if (mCancelable) {
+                cancel();
+            } else {
+                dismiss();
+            }
             event.startTracking();
             return true;
         }
@@ -712,11 +721,6 @@
                     }
                     break;
                 case KeyEvent.KEYCODE_ESCAPE:
-                    if (mCancelable) {
-                        cancel();
-                    } else {
-                        dismiss();
-                    }
                     return true;
             }
         }
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index d7aafa0..a884ab0 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -16,6 +16,8 @@
 
 package android.app.admin;
 
+import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
+
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
@@ -45,6 +47,12 @@
     public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
 
     /**
+     * String identifier for {@link DevicePolicyManager#setSecurityLoggingEnabled}.
+     */
+    @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+    public static final String SECURITY_LOGGING_POLICY = "securityLogging";
+
+    /**
      * String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
      */
     public static final String LOCK_TASK_POLICY = "lockTask";
@@ -174,6 +182,12 @@
     public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
 
     /**
+     * String identifier for {@link DevicePolicyManager#setRequiredPasswordComplexity}.
+     */
+    @FlaggedApi(Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
+    public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
+
+    /**
      * @hide
      */
     public static final String USER_RESTRICTION_PREFIX = "userRestriction_";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9d50810..c53b54c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -52,6 +52,7 @@
 import static android.Manifest.permission.SET_TIME;
 import static android.Manifest.permission.SET_TIME_ZONE;
 import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
 import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
 import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
@@ -13976,6 +13977,24 @@
      * privacy-sensitive events happening outside the managed profile would have been redacted
      * already.
      *
+     * Starting from {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, after the security logging
+     * policy has been set, {@link PolicyUpdateReceiver#onPolicySetResult(Context, String,
+     * Bundle, TargetUser, PolicyUpdateResult)} will notify the admin on whether the policy was
+     * successfully set or not. This callback will contain:
+     * <ul>
+     * <li> The policy identifier {@link DevicePolicyIdentifiers#SECURITY_LOGGING_POLICY}
+     * <li> The {@link TargetUser} that this policy relates to
+     * <li> The {@link PolicyUpdateResult}, which will be
+     * {@link PolicyUpdateResult#RESULT_POLICY_SET} if the policy was successfully set or the
+     * reason the policy failed to be set
+     * e.g. {@link PolicyUpdateResult#RESULT_FAILURE_CONFLICTING_ADMIN_POLICY})
+     * </ul>
+     * If there has been a change to the policy,
+     * {@link PolicyUpdateReceiver#onPolicyChanged(Context, String, Bundle, TargetUser,
+     * PolicyUpdateResult)} will notify the admin of this change. This callback will contain the
+     * same parameters as PolicyUpdateReceiver#onPolicySetResult and the {@link PolicyUpdateResult}
+     * will contain the reason why the policy changed.
+     *
      * @param admin Which device admin this request is associated with, or {@code null}
      *              if called by a delegated app.
      * @param enabled whether security logging should be enabled or not.
@@ -17330,4 +17349,46 @@
         }
         return new HashSet<>();
     }
+
+    /**
+     * Controls the maximum storage size allowed for policies associated with an admin.
+     * Setting a limit of -1 effectively removes any storage restrictions.
+     *
+     * @param storageLimit Maximum storage allowed in bytes. Use -1 to disable limits.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
+    public void setMaxPolicyStorageLimit(int storageLimit) {
+        if (mService != null) {
+            try {
+                mService.setMaxPolicyStorageLimit(mContext.getPackageName(), storageLimit);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Retrieves the current maximum storage limit for policies associated with an admin.
+     *
+     * @return The maximum storage limit in bytes, or -1 if no limit is enforced.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
+    public int getMaxPolicyStorageLimit() {
+        if (mService != null) {
+            try {
+                return mService.getMaxPolicyStorageLimit(mContext.getPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return -1;
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 304359b..07ee8de 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -333,4 +333,9 @@
      */
     public abstract List<EnforcingUser> getUserRestrictionSources(String restriction,
                 @UserIdInt int userId);
+
+    /**
+     * Enforces resolved security logging policy, should only be invoked from device policy engine.
+     */
+    public abstract void enforceSecurityLoggingPolicy(boolean enabled);
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f72fdc0..c4cbdd6 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -615,4 +615,7 @@
     int getContentProtectionPolicy(in ComponentName who, String callerPackageName);
 
     int[] getSubscriptionIds(String callerPackageName);
+
+    void setMaxPolicyStorageLimit(String packageName, int storageLimit);
+    int getMaxPolicyStorageLimit(String packageName);
 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7a4a3f9..9fa7362 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,5 +1,7 @@
 package android.app.assist;
 
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1278,7 +1280,7 @@
          *
          * @hide
          */
-        @FlaggedApi("autofill_credman_dev_integration")
+        @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
         @Nullable
         public GetCredentialRequest getCredentialManagerRequest() {
             return mGetCredentialRequest;
@@ -1291,7 +1293,7 @@
          * @hide
          *
          */
-        @FlaggedApi("autofill_credman_dev_integration")
+        @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
         @Nullable
         public OutcomeReceiver<GetCredentialResponse,
                 GetCredentialException> getCredentialManagerCallback() {
diff --git a/core/java/android/app/wearable/IWearableSensingManager.aidl b/core/java/android/app/wearable/IWearableSensingManager.aidl
index 3cbc8a2..f678022 100644
--- a/core/java/android/app/wearable/IWearableSensingManager.aidl
+++ b/core/java/android/app/wearable/IWearableSensingManager.aidl
@@ -17,6 +17,7 @@
 package android.app.wearable;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.RemoteCallback;
@@ -38,4 +39,8 @@
      void registerDataRequestObserver(int dataType, in PendingIntent dataRequestPendingIntent, in RemoteCallback statusCallback);
      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
      void unregisterDataRequestObserver(int dataType, in PendingIntent dataRequestPendingIntent, in RemoteCallback statusCallback);
+     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
+     void startHotwordRecognition(in ComponentName targetVisComponentName, in RemoteCallback statusCallback);
+     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)")
+     void stopHotwordRecognition(in RemoteCallback statusCallback);
 }
\ No newline at end of file
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index 3b281e9..637f677 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -28,6 +28,7 @@
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.companion.CompanionDeviceManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
@@ -92,9 +93,13 @@
     public static final int STATUS_SUCCESS = 1;
 
     /**
-     * The value of the status code that indicates one or more of the
-     * requested events are not supported.
+     * The value of the status code that indicates one or more of the requested events are not
+     * supported.
      */
+    // TODO(b/324635656): Deprecate this status code. Update Javadoc:
+    // @deprecated WearableSensingManager does not deal with events. Use {@link
+    // STATUS_UNSUPPORTED_OPERATION} instead for operations not supported by the implementation of
+    // {@link WearableSensingService}.
     public static final int STATUS_UNSUPPORTED = 2;
 
     /**
@@ -382,6 +387,83 @@
         }
     }
 
+    /**
+     * Requests the wearable to start hotword recognition.
+     *
+     * <p>When this method is called, the system will attempt to provide a {@link
+     * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}.
+     * After first-stage hotword is detected on a wearable, {@link WearableSensingService} should
+     * send the hotword audio to the {@link android.service.wearable.WearableHotwordAudioConsumer},
+     * which will forward the data to the {@link android.service.voice.HotwordDetectionService} for
+     * second-stage hotword validation. If hotword is detected there, the audio data will be
+     * forwarded to the {@link android.service.voice.VoiceInteractionService}.
+     *
+     * <p>If the {@code targetVisComponentName} provided here is not null, when {@link
+     * WearableSensingService} sends hotword audio to the {@link
+     * android.service.wearable.WearableHotwordAudioConsumer}, the system will check whether the
+     * {@link android.service.voice.VoiceInteractionService} at that time is {@code
+     * targetVisComponentName}. If not, the system will call {@link
+     * WearableSensingService#onActiveHotwordAudioStopRequested()} and will not forward the audio
+     * data to the current {@link android.service.voice.HotwordDetectionService} nor {@link
+     * android.service.voice.VoiceInteractionService}. The system will not send a status code to
+     * {@code statusConsumer} regarding the {@code targetVisComponentName} check. The caller is
+     * responsible for determining whether the system's {@link
+     * android.service.voice.VoiceInteractionService} is the same as {@code targetVisComponentName}.
+     * The check here is just a protection against race conditions.
+     *
+     * <p>Calling this method again will send a new {@link
+     * android.service.wearable.WearableHotwordAudioConsumer} to {@link WearableSensingService}. For
+     * audio data sent to the new consumer, the system will perform the above check using the newly
+     * provided {@code targetVisComponentName}. The {@link WearableSensingService} should not
+     * continue to use the previous consumers after receiving a new one.
+     *
+     * <p>If the {@code statusConsumer} returns {@link STATUS_SUCCESS}, the caller should call
+     * {@link #stopListeningForHotword(Executor, Consumer)} when it wants the wearable to stop
+     * listening for hotword. If the {@code statusConsumer} returns any other status code, a failure
+     * has occurred and calling {@link #stopListeningForHotword(Executor, Consumer)} is not
+     * required. The system will not retry listening automatically. The caller should call this
+     * method again if they want to retry.
+     *
+     * <p>If a failure occurred after the {@link statusConsumer} returns {@link STATUS_SUCCESS},
+     * {@link statusConsumer} will be invoked again with a status code other than {@link
+     * STATUS_SUCCESS}.
+     *
+     * @param targetVisComponentName The ComponentName of the target VoiceInteractionService.
+     * @param executor Executor on which to run the consumer callback.
+     * @param statusConsumer A consumer that handles the status codes.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
+    public void startHotwordRecognition(
+            @Nullable ComponentName targetVisComponentName,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+        try {
+            mService.startHotwordRecognition(
+                    targetVisComponentName, createStatusCallback(executor, statusConsumer));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Requests the wearable to stop hotword recognition.
+     *
+     * @param executor Executor on which to run the consumer callback.
+     * @param statusConsumer A consumer that handles the status codes.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
+    public void stopHotwordRecognition(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+        try {
+            mService.stopHotwordRecognition(createStatusCallback(executor, statusConsumer));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static RemoteCallback createStatusCallback(
             Executor executor, Consumer<Integer> statusConsumer) {
         return new RemoteCallback(
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c7d93bf..317fa58 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -142,3 +142,10 @@
     description: "Enable extra check to limit access to hidden prfiles data in Launcher apps APIs."
     bug: "321988638"
 }
+
+flag {
+    name: "reorder_wallpaper_during_user_switch"
+    namespace: "multiuser"
+    description: "Reorder loading home and lock screen wallpapers during a user switch."
+    bug: "324911115"
+}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 870546a..ba356bb 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -40,7 +40,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.CursorWindow_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.CursorWindow_host")
 public class CursorWindow extends SQLiteClosable implements Parcelable {
     private static final String STATS_TAG = "CursorWindowStats";
 
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index f2ef185..f7b4173 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -21,7 +21,6 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.admin.flags.Flags;
-import android.compat.annotation.UnsupportedAppUsage;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -127,12 +126,8 @@
 
     /**
      * Options for a lightweight bugreport intended to be taken for onboarding-related flows.
-     *
-     * @hide
      */
-    @TestApi
     @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
-    @UnsupportedAppUsage
     public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
 
     /**
@@ -180,10 +175,7 @@
      * The bugreport may be retrieved multiple times using
      * {@link BugreportManager#retrieveBugreport(
      * String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
-     *
-     * @hide
      */
-    @TestApi
     @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
     public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL =
             IDumpstate.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL;
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index fbec518..3950c25 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -42,7 +42,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.MessageQueue_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
 public final class MessageQueue {
     private static final String TAG = "MessageQueue";
     private static final boolean DEBUG = false;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8e860c3..ccfb632 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -233,7 +233,8 @@
  * {@link #readSparseArray(ClassLoader, Class)}.
  */
 @RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.Parcel_host")
+@RavenwoodNativeSubstitutionClass(
+        "com.android.platform.test.ravenwood.nativesubstitution.Parcel_host")
 public final class Parcel {
 
     private static final boolean DEBUG_RECYCLE = false;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 6532d5c..17dfdda 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -75,7 +75,8 @@
  * you to close it when done with it.
  */
 @RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.ParcelFileDescriptor_host")
+@RavenwoodNativeSubstitutionClass(
+        "com.android.platform.test.ravenwood.nativesubstitution.ParcelFileDescriptor_host")
 public class ParcelFileDescriptor implements Parcelable, Closeable {
     private static final String TAG = "ParcelFileDescriptor";
 
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index a818919..0a38691 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -56,7 +56,8 @@
  */
 @SystemApi
 @RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.SystemProperties_host")
+@RavenwoodNativeSubstitutionClass(
+        "com.android.platform.test.ravenwood.nativesubstitution.SystemProperties_host")
 public class SystemProperties {
     private static final String TAG = "SystemProperties";
     private static final boolean TRACK_KEY_ACCESS = false;
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 43163b3..7631454 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -15,10 +15,11 @@
 }
 
 flag {
-    name: "mgf1_digest_setter"
+    name: "mgf1_digest_setter_v2"
     namespace: "hardware_backed_security"
     description: "Feature flag for mgf1 digest setter in key generation and import parameters."
     bug: "308378912"
+    is_fixed_read_only: true
 }
 
 flag {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 94d8516..a08264e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -22,6 +22,7 @@
 import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
 
 import android.annotation.ElapsedRealtimeLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -432,7 +433,10 @@
         @ElapsedRealtimeLong
         private final long mHalEventReceivedMillis;
 
-        private EventPayload(boolean captureAvailable,
+        private final boolean mIsRecognitionStopped;
+
+        private EventPayload(
+                boolean captureAvailable,
                 @Nullable AudioFormat audioFormat,
                 int captureSession,
                 @DataFormat int dataFormat,
@@ -440,7 +444,8 @@
                 @Nullable HotwordDetectedResult hotwordDetectedResult,
                 @Nullable ParcelFileDescriptor audioStream,
                 @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras,
-                @ElapsedRealtimeLong long halEventReceivedMillis) {
+                @ElapsedRealtimeLong long halEventReceivedMillis,
+                boolean isRecognitionStopped) {
             mCaptureAvailable = captureAvailable;
             mCaptureSession = captureSession;
             mAudioFormat = audioFormat;
@@ -450,6 +455,7 @@
             mAudioStream = audioStream;
             mKephraseExtras = keyphraseExtras;
             mHalEventReceivedMillis = halEventReceivedMillis;
+            mIsRecognitionStopped = isRecognitionStopped;
         }
 
         /**
@@ -592,6 +598,12 @@
             return mHalEventReceivedMillis;
         }
 
+        /** Returns whether the system has stopped hotword recognition because of this detection. */
+        @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+        public boolean isRecognitionStopped() {
+            return mIsRecognitionStopped;
+        }
+
         /**
          * Builder class for {@link EventPayload} objects
          *
@@ -610,6 +622,8 @@
             private List<KeyphraseRecognitionExtra> mKeyphraseExtras = Collections.emptyList();
             @ElapsedRealtimeLong
             private long mHalEventReceivedMillis = -1;
+            // default to true to keep prior behavior
+            private boolean mIsRecognitionStopped = true;
 
             public Builder() {}
 
@@ -746,13 +760,31 @@
             }
 
             /**
+             * Sets whether the system has stopped hotword recognition because of this detection.
+             */
+            @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+            @NonNull
+            public Builder setIsRecognitionStopped(boolean isRecognitionStopped) {
+                mIsRecognitionStopped = isRecognitionStopped;
+                return this;
+            }
+
+            /**
              * Builds an {@link EventPayload} instance
              */
             @NonNull
             public EventPayload build() {
-                return new EventPayload(mCaptureAvailable, mAudioFormat, mCaptureSession,
-                        mDataFormat, mData, mHotwordDetectedResult, mAudioStream,
-                        mKeyphraseExtras, mHalEventReceivedMillis);
+                return new EventPayload(
+                        mCaptureAvailable,
+                        mAudioFormat,
+                        mCaptureSession,
+                        mDataFormat,
+                        mData,
+                        mHotwordDetectedResult,
+                        mAudioStream,
+                        mKeyphraseExtras,
+                        mHalEventReceivedMillis,
+                        mIsRecognitionStopped);
             }
         }
     }
@@ -786,14 +818,20 @@
 
         /**
          * Called when the keyphrase is spoken.
-         * This implicitly stops listening for the keyphrase once it's detected.
-         * Clients should start a recognition again once they are done handling this
-         * detection.
          *
-         * @param eventPayload Payload data for the detection event.
-         *        This may contain the trigger audio, if requested when calling
-         *        {@link AlwaysOnHotwordDetector#startRecognition(int)}.
+         * <p>This implicitly stops listening for the keyphrase once it's detected. Clients should
+         * start a recognition again once they are done handling this detection.
+         *
+         * @param eventPayload Payload data for the detection event. This may contain the trigger
+         *     audio, if requested when calling {@link
+         *     AlwaysOnHotwordDetector#startRecognition(int)}.
          */
+        // TODO(b/324635656): Update Javadoc for 24Q3 release:
+        // 1. Prepend to the first paragraph:
+        //     If {@code eventPayload.isRecognitionStopped()} returns true, this...
+        // 2. Append to the description for @param eventPayload:
+        //     ...or if the audio comes from {@link
+        //     android.service.wearable.WearableSensingService}.
         public abstract void onDetected(@NonNull EventPayload eventPayload);
 
         /**
@@ -1632,6 +1670,20 @@
         }
 
         @Override
+        public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+            Slog.i(TAG, "onKeyphraseDetectedFromExternalSource");
+            EventPayload.Builder eventPayloadBuilder = new EventPayload.Builder();
+            if (android.app.wearable.Flags.enableHotwordWearableSensingApi()) {
+                eventPayloadBuilder.setIsRecognitionStopped(false);
+            }
+            Message.obtain(
+                            mHandler,
+                            MSG_HOTWORD_DETECTED,
+                            eventPayloadBuilder.setHotwordDetectedResult(result).build())
+                    .sendToTarget();
+        }
+
+        @Override
         public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
             Slog.w(TAG, "Generic sound trigger event detected at AOHD: " + event);
         }
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index ccf8b67..60e9de7 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -19,6 +19,7 @@
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.DurationMillisLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -79,6 +80,16 @@
     private static final long UPDATE_TIMEOUT_MILLIS = 20000;
 
     /**
+     * The PersistableBundle options key used in {@link #onDetect(ParcelFileDescriptor, AudioFormat,
+     * PersistableBundle, Callback)} to indicate whether the system will close the audio stream
+     * after {@code Callback} is invoked.
+     */
+    @FlaggedApi(android.app.wearable.Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    public static final String KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK =
+            "android.service.voice.HotwordDetectionService."
+                    + "KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK";
+
+    /**
      * Feature flag for Attention Service.
      *
      * @hide
@@ -364,6 +375,11 @@
      * PersistableBundle)}.
      * @param callback The callback to use for responding to the detection request.
      */
+    // TODO(b/324635656): Update Javadoc for 24Q3 release. Change the last paragraph to:
+    // <p>Upon invoking the {@code callback}, the system will send the detection result to
+    // the {@link HotwordDetector}'s callback. If {@code
+    // options.getBoolean(KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK, true)} returns true,
+    // the system will also close the {@code audioStream} after {@code callback} is invoked.
     public void onDetect(
             @NonNull ParcelFileDescriptor audioStream,
             @NonNull AudioFormat audioFormat,
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index f1bc792..a835b0f 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -223,6 +223,13 @@
         }
 
         @Override
+        public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+            if (DEBUG) {
+                Slog.i(TAG, "Ignored #onKeyphraseDetectedFromExternalSource event");
+            }
+        }
+
+        @Override
         public void onGenericSoundTriggerDetected(
                 SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException {
             if (DEBUG) {
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 23847fe..1eb4d67 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -414,6 +414,13 @@
         }
 
         @Override
+        public void onKeyphraseDetectedFromExternalSource(HotwordDetectedResult result) {
+            if (DEBUG) {
+                Slog.i(TAG, "Ignored #onKeyphraseDetectedFromExternalSource event");
+            }
+        }
+
+        @Override
         public void onGenericSoundTriggerDetected(
                 SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException {
             if (DEBUG) {
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index 270f848..7d27733 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -19,14 +19,17 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.media.AudioFormat;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 
 import com.android.internal.annotations.Immutable;
 
 /**
- * @hide
- * Private interface to the VoiceInteractionManagerService for use by ActivityManagerService.
+ * @hide Private interface to the VoiceInteractionManagerService for use within system_server.
  */
 public abstract class VoiceInteractionManagerInternal {
 
@@ -77,6 +80,25 @@
     public abstract void onPreCreatedUserConversion(@UserIdInt int userId);
 
     /**
+     * Called by {@link com.android.server.wearable.WearableSensingManagerPerUserService} when a
+     * wearable starts sending audio data for hotword detection.
+     *
+     * @param audioStream The audio data.
+     * @param audioFormat The format of the audio data.
+     * @param options Options supporting hotword detection.
+     * @param targetVisComponentName The target VoiceInteractionService ComponentName
+     * @param userId The user ID of the calling wearable service
+     * @param callback The callback to notify the caller of the hotword detection result.
+     */
+    public abstract void startListeningFromWearable(
+            ParcelFileDescriptor audioStream,
+            AudioFormat audioFormat,
+            PersistableBundle options,
+            ComponentName targetVisComponentName,
+            int userId,
+            WearableHotwordDetectionCallback callback);
+
+    /**
      * Provides the uids of the currently active
      * {@link android.service.voice.HotwordDetectionService} and its owning package. The
      * HotwordDetectionService is an isolated service, so it has a separate uid.
@@ -101,4 +123,20 @@
             return mOwnerUid;
         }
     }
+
+    /**
+     * Callback for returning the detected hotword result to the wearable.
+     *
+     * @hide
+     */
+    public interface WearableHotwordDetectionCallback {
+        /** Called when hotword is detected. */
+        void onDetected();
+
+        /** Called when hotword is not detected. */
+        void onRejected();
+
+        /** Called when an unexpected error occurs. */
+        void onError(String errorMessage);
+    }
 }
diff --git a/core/java/android/service/wearable/IWearableSensingService.aidl b/core/java/android/service/wearable/IWearableSensingService.aidl
index f67dcff..22d8fda 100644
--- a/core/java/android/service/wearable/IWearableSensingService.aidl
+++ b/core/java/android/service/wearable/IWearableSensingService.aidl
@@ -33,6 +33,10 @@
     void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback);
     void registerDataRequestObserver(int dataType, in RemoteCallback dataRequestCallback, int dataRequestObserverId, in String packageName, in RemoteCallback statusCallback);
     void unregisterDataRequestObserver(int dataType, int dataRequestObserverId, in String packageName, in RemoteCallback statusCallback);
+    void startHotwordRecognition(in RemoteCallback wearableHotwordCallback, in RemoteCallback statusCallback);
+    void stopHotwordRecognition(in RemoteCallback statusCallback);
+    void onValidatedByHotwordDetectionService();
+    void stopActiveHotwordAudio();
     void startDetection(in AmbientContextEventRequest request, in String packageName,
             in RemoteCallback detectionResultCallback, in RemoteCallback statusCallback);
     void stopDetection(in String packageName);
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index bb6e030..808c3ae 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -37,6 +37,7 @@
 import android.os.SharedMemory;
 import android.service.ambientcontext.AmbientContextDetectionResult;
 import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
+import android.service.voice.HotwordAudioStream;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -85,6 +86,14 @@
             "android.app.wearable.WearableSensingStatusBundleKey";
 
     /**
+     * The bundle key for hotword audio stream, used in {@code RemoteCallback#sendResult}.
+     *
+     * @hide
+     */
+    public static final String HOTWORD_AUDIO_STREAM_BUNDLE_KEY =
+            "android.app.wearable.HotwordAudioStreamBundleKey";
+
+    /**
      * The {@link Intent} that must be declared as handled by the service. To be supported, the
      * service must also require the
      * {@link android.Manifest.permission#BIND_WEARABLE_SENSING_SERVICE}
@@ -181,6 +190,50 @@
                             dataType, packageName, dataRequester, statusConsumer);
                 }
 
+                @Override
+                public void startHotwordRecognition(
+                        RemoteCallback wearableHotwordCallback, RemoteCallback statusCallback) {
+                    Consumer<HotwordAudioStream> hotwordAudioConsumer =
+                            (hotwordAudioStream) -> {
+                                Bundle bundle = new Bundle();
+                                bundle.putParcelable(
+                                        HOTWORD_AUDIO_STREAM_BUNDLE_KEY, hotwordAudioStream);
+                                wearableHotwordCallback.sendResult(bundle);
+                            };
+                    Consumer<Integer> statusConsumer =
+                            response -> {
+                                Bundle bundle = new Bundle();
+                                bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response);
+                                statusCallback.sendResult(bundle);
+                            };
+                    WearableSensingService.this.onStartHotwordRecognition(
+                            hotwordAudioConsumer, statusConsumer);
+                }
+
+                /** {@inheritDoc} */
+                @Override
+                public void stopHotwordRecognition(RemoteCallback statusCallback) {
+                    Consumer<Integer> statusConsumer =
+                            response -> {
+                                Bundle bundle = new Bundle();
+                                bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response);
+                                statusCallback.sendResult(bundle);
+                            };
+                    WearableSensingService.this.onStopHotwordRecognition(statusConsumer);
+                }
+
+                /** {@inheritDoc} */
+                @Override
+                public void onValidatedByHotwordDetectionService() {
+                    WearableSensingService.this.onValidatedByHotwordDetectionService();
+                }
+
+                /** {@inheritDoc} */
+                @Override
+                public void stopActiveHotwordAudio() {
+                    WearableSensingService.this.onStopHotwordAudioStream();
+                }
+
                 /** {@inheritDoc} */
                 @Override
                 public void startDetection(
@@ -377,6 +430,100 @@
     }
 
     /**
+     * Called when the wearable is requested to start hotword recognition.
+     *
+     * <p>This method is expected to be overridden by a derived class. The implementation should
+     * store the {@code hotwordAudioConsumer} and send it the audio data when first-stage hotword is
+     * detected from the wearable. It should also send a {@link
+     * WearableSensingManager#STATUS_SUCCESS} status code to the {@code statusConsumer} unless it
+     * encounters an error condition described by a status code listed in {@link
+     * WearableSensingManager}, such as {@link WearableSensingManager#STATUS_WEARABLE_UNAVAILABLE},
+     * in which case it should return the corresponding status code.
+     *
+     * <p>The implementation should also store the {@code statusConsumer}. If the wearable stops
+     * listening for hotword for any reason other than {@link #onStopListeningForHotword(Consumer)}
+     * being invoked, it should send an appropriate status code listed in {@link
+     * WearableSensingManager} to {@code statusConsumer}. If the error condition cannot be described
+     * by any of those status codes, it should send a {@link WearableSensingManager#STATUS_UNKNOWN}.
+     *
+     * <p>If this method is called again, the implementation should use the new {@code
+     * hotwordAudioConsumer} and discard any previous ones it received.
+     *
+     * <p>At this time, the {@code timestamp} field in the {@link HotwordAudioStream} is not used
+     * and will be discarded by the system.
+     *
+     * @param hotwordAudioConsumer The consumer for the wearable hotword audio data.
+     * @param statusConsumer The consumer for the service status.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @BinderThread
+    public void onStartHotwordRecognition(
+            @NonNull Consumer<HotwordAudioStream> hotwordAudioConsumer,
+            @NonNull Consumer<Integer> statusConsumer) {
+        if (Flags.enableUnsupportedOperationStatusCode()) {
+            statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);
+        }
+    }
+
+    /**
+     * Called when the wearable is requested to stop hotword recognition.
+     *
+     * <p>This method is expected to be overridden by a derived class. It should send a {@link
+     * WearableSensingManager#STATUS_SUCCESS} status code to the {@code statusConsumer} unless it
+     * encounters an error condition described by a status code listed in {@link
+     * WearableSensingManager}, such as {@link WearableSensingManager#STATUS_WEARABLE_UNAVAILABLE},
+     * in which case it should return the corresponding status code.
+     *
+     * @param statusConsumer The consumer for the service status.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @BinderThread
+    public void onStopHotwordRecognition(@NonNull Consumer<Integer> statusConsumer) {
+        if (Flags.enableUnsupportedOperationStatusCode()) {
+            statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);
+        }
+    }
+
+    /**
+     * Called when hotword audio data sent to the {@code hotwordAudioConsumer} in {@link
+     * #onStartListeningForHotword(Consumer, Consumer)} is accepted by the
+     * {@link android.service.voice.HotwordDetectionService} as valid hotword.
+     *
+     * <p>After the implementation of this class sends the hotword audio data to the {@code
+     * hotwordAudioConsumer} in {@link #onStartListeningForHotword(Consumer,
+     * Consumer)}, the system will forward the data into {@link
+     * android.service.voice.HotwordDetectionService} (which runs in an isolated process) for
+     * second-stage hotword detection. If accepted as valid hotword there, this method will be
+     * called, and then the system will send the data to the currently active {@link
+     * android.service.voice.AlwaysOnHotwordDetector} (which may not run in an isolated process).
+     *
+     * <p>This method is expected to be overridden by a derived class. The implementation must
+     * request the wearable to turn on the microphone indicator to notify the user that audio data
+     * is being used outside of the isolated environment.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @BinderThread
+    public void onValidatedByHotwordDetectionService() {}
+
+    /**
+     * Called when the currently active hotword audio stream is no longer needed.
+     *
+     * <p>This method can be called as a result of hotword rejection by {@link
+     * android.service.voice.HotwordDetectionService}, or the {@link
+     * android.service.voice.AlwaysOnHotwordDetector} closing the data stream it received, or a
+     * non-recoverable error occurred before the data reaches the {@link
+     * android.service.voice.HotwordDetectionService} or the {@link
+     * android.service.voice.AlwaysOnHotwordDetector}.
+     *
+     * <p>This method is expected to be overridden by a derived class. The implementation should
+     * stop sending hotword audio data to the {@code hotwordAudioConsumer} in {@link
+     * #onStartListeningForHotword(Consumer, Consumer)}
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
+    @BinderThread
+    public void onStopHotwordAudioStream() {}
+
+    /**
      * Called when a client app requests starting detection of the events in the request. The
      * implementation should keep track of whether the user has explicitly consented to detecting
      * the events using on-going ambient sensor (e.g. microphone), and agreed to share the
@@ -460,4 +607,6 @@
             statusCallback.sendResult(bundle);
         };
     }
+
+
 }
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index d2c5975..0a73fd1 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -50,7 +50,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.EventLog_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.EventLog_host")
 public class EventLog {
     /** @hide */ public EventLog() {}
 
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 31576c5..b33214d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -73,7 +73,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.Log_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
 public final class Log {
     /** @hide */
     @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index ffe0c71..9413f5c 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -19,10 +19,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UiThread;
+import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.HardwareBuffer;
-import android.os.IBinder;
+import android.os.Looper;
 import android.window.InputTransferToken;
 import android.window.SurfaceSyncGroup;
 
@@ -180,32 +181,25 @@
     }
 
     /**
-     * Gets the token used for associating this {@link AttachedSurfaceControl} with
-     * {@link SurfaceControlViewHost} instances.
-     *
-     * <p>This token should be passed to {@link SurfaceControlViewHost}'s constructor.
-     * This token will be {@code null} if the window does not have an input channel.
-     *
-     * @return The SurfaceControlViewHost link token.
-     */
-    @Nullable
-    @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API)
-    default IBinder getHostToken() {
-        throw new UnsupportedOperationException("The getHostToken needs to be "
-            + "implemented before making this call.");
-    }
-
-    /**
      * Gets the token used for associating this {@link AttachedSurfaceControl} with an embedded
      * {@link SurfaceControlViewHost} or {@link SurfaceControl}
      *
-     * @return The SurfaceControlViewHost link token.  This can return {@code null} if the
-     * {@link AttachedSurfaceControl} was created with no registered input
-     * @hide
+     * <p>This token should be passed to
+     * {@link SurfaceControlViewHost#SurfaceControlViewHost(Context, Display, InputTransferToken)}
+     * or
+     * {@link WindowManager#registerBatchedSurfaceControlInputReceiver(int, InputTransferToken,
+     * SurfaceControl, Choreographer, SurfaceControlInputReceiver)} or
+     * {@link WindowManager#registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken,
+     * SurfaceControl, Looper, SurfaceControlInputReceiver)}
+     *
+     * @return The SurfaceControlViewHost link token.
+     * @throws IllegalStateException if the {@link AttachedSurfaceControl} was created with no
+     * registered input
      */
-    @Nullable
+    @NonNull
+    @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
     default InputTransferToken getInputTransferToken() {
-        throw new UnsupportedOperationException("The getHostToken needs to be "
+        throw new UnsupportedOperationException("The getInputTransferToken needs to be "
                 + "implemented before making this call.");
     }
 
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 58765b4..1dd9cbb 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -33,6 +34,8 @@
 import android.window.InputTransferToken;
 import android.window.WindowTokenClient;
 
+import com.android.window.flags.Flags;
+
 import dalvik.system.CloseGuard;
 
 import java.util.Objects;
@@ -347,6 +350,25 @@
             @Nullable IBinder hostToken) {
         this(context, display, hostToken == null ? null : new InputTransferToken(hostToken),
                 "untracked");
+
+    }
+
+    /**
+     * Construct a new SurfaceControlViewHost. The root Surface will be
+     * allocated internally and is accessible via getSurfacePackage().
+     * <p>
+     * The hostInputTransferToken parameter allows the host and embedded to be associated with
+     * each other to allow transferring touch gesture and focus. This is also used for ANR
+     * reporting. It's accessible from {@link AttachedSurfaceControl#getInputTransferToken()}.
+     *
+     * @param context                The Context object for your activity or application.
+     * @param display                The Display the hierarchy will be placed on.
+     * @param hostInputTransferToken The host input transfer token, as discussed above.
+     */
+    @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+    public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
+            @Nullable InputTransferToken hostInputTransferToken) {
+        this(context, display, hostInputTransferToken, "untracked");
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 254c4ae..25ade62 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,6 +18,7 @@
 
 import static android.content.res.Resources.ID_NULL;
 import static android.os.Trace.TRACE_TAG_APP;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
 import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
@@ -6995,7 +6996,7 @@
      *
      * @see #setCredentialManagerRequest
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public void clearCredentialManagerRequest() {
         if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) {
             Log.v(AUTOFILL_LOG_TAG, "clearCredentialManagerRequest called");
@@ -7027,7 +7028,7 @@
      * @param callback to be invoked when either a response or an exception needs to be
      *                 propagated for the given view
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public void setCredentialManagerRequest(@NonNull GetCredentialRequest request,
             @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
         Preconditions.checkNotNull(request, "request must not be null");
@@ -9944,7 +9945,7 @@
      *
      * @return The credential request associated with this View.
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     @Nullable
     public final GetCredentialRequest getCredentialManagerRequest() {
         if (mViewCredentialHandler == null) {
@@ -9968,7 +9969,7 @@
      * @return The callback associated with this view that will be invoked on a response from
      * {@link CredentialManager} .
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     @Nullable
     public final OutcomeReceiver<GetCredentialResponse,
             GetCredentialException> getCredentialManagerCallback() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 28a7334..657c8e6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -103,7 +103,6 @@
 import android.animation.AnimationHandler;
 import android.animation.LayoutTransition;
 import android.annotation.AnyThread;
-import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -240,7 +239,6 @@
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.SurfaceCallbackHelper;
 import com.android.modules.expresslog.Counter;
-import com.android.window.flags.Flags;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -11220,25 +11218,15 @@
     }
 
     /**
-     * @return Returns a token used for associating the root surface
-     * to {@link SurfaceControlViewHost}.
-     */
-    @Nullable
-    @Override
-    @FlaggedApi(Flags.FLAG_GET_HOST_TOKEN_API)
-    public IBinder getHostToken() {
-        return getInputToken();
-    }
-
-    /**
      * {@inheritDoc}
      */
-    @Nullable
+    @NonNull
     @Override
     public InputTransferToken getInputTransferToken() {
         IBinder inputToken = getInputToken();
         if (inputToken == null) {
-            return null;
+            throw new IllegalStateException(
+                    "Called getInputTransferToken for Window with no input channel");
         }
         return new InputTransferToken(inputToken);
     }
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index d86cc4a..131fca7 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -361,7 +363,7 @@
      * {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
      */
     @Nullable
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public GetCredentialRequest getCredentialManagerRequest() {
         return null;
     }
@@ -376,7 +378,7 @@
      * {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
      */
     @Nullable
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public OutcomeReceiver<
             GetCredentialResponse, GetCredentialException> getCredentialManagerCallback() {
         return null;
@@ -551,7 +553,7 @@
      * @param request the request to be fired
      * @param callback the callback where the response or exception, is returned
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public void setCredentialManagerRequest(@NonNull GetCredentialRequest request,
             @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {}
 
@@ -559,7 +561,7 @@
      * Clears the credential request previously set through
      * {@link ViewStructure#setCredentialManagerRequest(GetCredentialRequest, OutcomeReceiver)}
      */
-    @FlaggedApi("autofill_credman_dev_integration")
+    @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
     public void clearCredentialManagerRequest() {}
 
     /**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 58fb273..0302a0d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -123,6 +123,7 @@
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.window.InputTransferToken;
 import android.window.TaskFpsCallback;
 import android.window.TrustedPresentationThresholds;
 
@@ -6097,25 +6098,28 @@
      * receive batched input event. For those events that are batched, the invocation will happen
      * once per {@link Choreographer} frame, and other input events will be delivered immediately.
      * This is different from
-     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
-     * SurfaceControlInputReceiver)} in that the input events are received batched. The caller must
-     * invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
-     * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
+     * { #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+     * Looper, SurfaceControlInputReceiver)} in that the input events are received batched. The
+     * caller must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up
+     * the resources when no longer needing to use the {@link SurfaceControlInputReceiver}
      *
-     * @param displayId      The display that the SurfaceControl will be placed on. Input will
-     *                       only work
-     *                       if SurfaceControl is on that display and that display was touched.
-     * @param surfaceControl The SurfaceControl to register the InputChannel for
-     * @param hostToken      The host token to link the InputChannel for. This is primarily for ANRs
-     *                       to ensure the host receives the ANR if any issues with touch on the
-     *                       InputChannel
-     * @param choreographer  The Choreographer used for batching. This should match the rendering
-     *                       Choreographer.
-     * @param receiver       The SurfaceControlInputReceiver that will receive the input events
+     * @param displayId              The display that the SurfaceControl will be placed on. Input
+     *                               will only work if SurfaceControl is on that display and that
+     *                               display  was touched.
+     * @param surfaceControl         The SurfaceControl to register the InputChannel for
+     * @param hostInputTransferToken The host token to link the embedded. This is used to handle
+     *                               transferring touch gesture from host to embedded and for ANRs
+     *                               to ensure the host receives the ANR if any issues with
+     *                               touch on the embedded.
+     * @param choreographer          The Choreographer used for batching. This should match the
+     *                               rendering Choreographer.
+     * @param receiver               The SurfaceControlInputReceiver that will receive the input
+     *                               events
      */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
     default void registerBatchedSurfaceControlInputReceiver(int displayId,
-            @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+            @NonNull InputTransferToken hostInputTransferToken,
+            @NonNull SurfaceControl surfaceControl,
             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
         throw new UnsupportedOperationException(
                 "registerBatchedSurfaceControlInputReceiver is not implemented");
@@ -6123,26 +6127,30 @@
 
     /**
      * Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will
-     * receive every input event. This is different than calling @link
-     * #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
-     * SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller
-     * must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
-     * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
+     * receive every input event. This is different than calling
+     * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+     * Choreographer, SurfaceControlInputReceiver)} in that the input events are received
+     * unbatched.
+     * The caller must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to
+     * clean up the resources when no longer needing to use the {@link SurfaceControlInputReceiver}
      *
-     * @param displayId      The display that the SurfaceControl will be placed on. Input will only
-     *                       work if SurfaceControl is on that display and that display was
-     *                       touched.
-     * @param hostToken      The host token to link the InputChannel for. This is primarily for ANRs
-     *                       to ensure the host receives the ANR if any issues with touch on the
-     *                       InputChannel
-     * @param surfaceControl The SurfaceControl to register the InputChannel for
-     * @param looper         The looper to use when invoking callbacks.
-     * @param receiver       The SurfaceControlInputReceiver that will receive the input events
-     **/
+     * @param displayId              The display that the SurfaceControl will be placed on. Input
+     *                               will only work if SurfaceControl is on that display and that
+     *                               display  was touched.
+     * @param surfaceControl         The SurfaceControl to register the InputChannel for
+     * @param hostInputTransferToken The host token to link the embedded. This is used to handle
+     *                               transferring touch gesture from host to embedded and for ANRs
+     *                               to ensure the host receives the ANR if any issues with
+     *                               touch on the embedded.
+     * @param looper                 The looper to use when invoking callbacks.
+     * @param receiver               The SurfaceControlInputReceiver that will receive the input
+     *                               events.
+     */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
     default void registerUnbatchedSurfaceControlInputReceiver(int displayId,
-            @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
-            @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
+            @NonNull InputTransferToken hostInputTransferToken,
+            @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
+            @NonNull SurfaceControlInputReceiver receiver) {
         throw new UnsupportedOperationException(
                 "registerUnbatchedSurfaceControlInputReceiver is not implemented");
     }
@@ -6152,10 +6160,10 @@
      * specified token.
      * <p>
      * Must be called on the same {@link Looper} thread to which was passed to the
-     * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl,
+     * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
      * Choreographer,
      * SurfaceControlInputReceiver)} or
-     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl, Looper,
      * SurfaceControlInputReceiver)}
      *
      * @param surfaceControl The SurfaceControl to remove and unregister the input channel for.
@@ -6171,7 +6179,7 @@
      * if the SurfaceControl was registered for input via
      * { #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
      * SurfaceControlInputReceiver)} or
-     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl, Looper,
      * SurfaceControlInputReceiver)}.
      * <p>
      * This is helpful for testing to ensure the test waits for the layer to be registered with
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2fb5213..1e3d062 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -535,19 +535,19 @@
 
     @Override
     public void registerBatchedSurfaceControlInputReceiver(int displayId,
-            @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
-            @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
-        mGlobal.registerBatchedSurfaceControlInputReceiver(displayId,
-                new InputTransferToken(hostToken),
+            @NonNull InputTransferToken hostInputTransferToken,
+            @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer,
+            @NonNull SurfaceControlInputReceiver receiver) {
+        mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
                 surfaceControl, choreographer, receiver);
     }
 
     @Override
-    public void registerUnbatchedSurfaceControlInputReceiver(
-            int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
-            @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
-        mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId,
-                new InputTransferToken(hostToken),
+    public void registerUnbatchedSurfaceControlInputReceiver(int displayId,
+            @NonNull InputTransferToken hostInputTransferToken,
+            @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
+            @NonNull SurfaceControlInputReceiver receiver) {
+        mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
                 surfaceControl, looper, receiver);
     }
 
diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java
index 0601b2a..bed0e0e 100644
--- a/core/java/android/window/InputTransferToken.java
+++ b/core/java/android/window/InputTransferToken.java
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.os.Binder;
 import android.os.IBinder;
@@ -23,13 +24,15 @@
 import android.os.Parcelable;
 import android.view.SurfaceControlViewHost;
 
+import com.android.window.flags.Flags;
+
 import java.util.Objects;
 
 /**
  * A token that can be used to request focus on or to transfer touch gesture to a
  * {@link SurfaceControlViewHost} or {@link android.view.SurfaceControl} that has an input channel.
- * @hide
  */
+@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
 public final class InputTransferToken implements Parcelable {
     /**
      * @hide
diff --git a/core/java/android/window/TrustedPresentationThresholds.java b/core/java/android/window/TrustedPresentationThresholds.java
index 90f8834..a30c8fa 100644
--- a/core/java/android/window/TrustedPresentationThresholds.java
+++ b/core/java/android/window/TrustedPresentationThresholds.java
@@ -19,15 +19,15 @@
 import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
-import android.annotation.SuppressLint;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.view.SurfaceControl;
 
 import androidx.annotation.NonNull;
 
 import com.android.window.flags.Flags;
 
+import java.util.Objects;
+
 /**
  * Threshold values that are sent with
  * {@link android.view.WindowManager#registerTrustedPresentationListener(IBinder,
@@ -36,33 +36,53 @@
 @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
 public final class TrustedPresentationThresholds implements Parcelable {
     /**
-     * The min alpha the {@link SurfaceControl} is required to have to be considered inside the
+     * The min alpha the Window is required to have to be considered inside the
      * threshold.
      */
     @FloatRange(from = 0f, fromInclusive = false, to = 1f)
-    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
-    @SuppressLint("InternalField") // simple data class
-    public final float minAlpha;
+    private final float mMinAlpha;
 
     /**
-     * The min fraction of the SurfaceControl that was presented to the user to be considered
+     * The min fraction of the Window that was presented to the user to be considered
      * inside the threshold.
      */
     @FloatRange(from = 0f, fromInclusive = false, to = 1f)
-    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
-    @SuppressLint("InternalField") // simple data class
-    public final float minFractionRendered;
+    private final float mMinFractionRendered;
 
     /**
-     * The time in milliseconds required for the {@link SurfaceControl} to be in the threshold.
+     * The time in milliseconds required for the Window to be in the threshold.
      */
     @IntRange(from = 1)
+    private final int mStabilityRequirementMs;
+
+    /**
+     * The min alpha the Window is required to have to be considered inside the
+     * threshold.
+     */
     @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
-    @SuppressLint("InternalField") // simple data class
-    public final int stabilityRequirementMs;
+    public @FloatRange(from = 0f, fromInclusive = false, to = 1f) float getMinAlpha() {
+        return mMinAlpha;
+    }
+
+    /**
+     * The min fraction of the Window that was presented to the user to be considered
+     * inside the threshold.
+     */
+    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+    public @FloatRange(from = 0f, fromInclusive = false, to = 1f) float getMinFractionRendered() {
+        return mMinFractionRendered;
+    }
+
+    /**
+     * The time in milliseconds required for the Window to be in the threshold.
+     */
+    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+    public @IntRange(from = 1) int getStabilityRequirementMillis() {
+        return mStabilityRequirementMs;
+    }
 
     private void checkValid() {
-        if (minAlpha <= 0 || minFractionRendered <= 0 || stabilityRequirementMs < 1) {
+        if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
             throw new IllegalArgumentException(
                     "TrustedPresentationThresholds values are invalid");
         }
@@ -71,23 +91,23 @@
     /**
      * Creates a new TrustedPresentationThresholds.
      *
-     * @param minAlpha               The min alpha the {@link SurfaceControl} is required to
+     * @param minAlpha               The min alpha the Window is required to
      *                               have to be considered inside the
      *                               threshold.
-     * @param minFractionRendered    The min fraction of the SurfaceControl that was presented
+     * @param minFractionRendered    The min fraction of the Window that was presented
      *                               to the user to be considered
      *                               inside the threshold.
      * @param stabilityRequirementMs The time in milliseconds required for the
-     *                               {@link SurfaceControl} to be in the threshold.
+     *                               Window to be in the threshold.
      */
     @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
     public TrustedPresentationThresholds(
             @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
             @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
             @IntRange(from = 1) int stabilityRequirementMs) {
-        this.minAlpha = minAlpha;
-        this.minFractionRendered = minFractionRendered;
-        this.stabilityRequirementMs = stabilityRequirementMs;
+        this.mMinAlpha = minAlpha;
+        this.mMinFractionRendered = minFractionRendered;
+        this.mStabilityRequirementMs = stabilityRequirementMs;
         checkValid();
     }
 
@@ -95,18 +115,18 @@
     @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
     public String toString() {
         return "TrustedPresentationThresholds { "
-                + "minAlpha = " + minAlpha + ", "
-                + "minFractionRendered = " + minFractionRendered + ", "
-                + "stabilityRequirementMs = " + stabilityRequirementMs
+                + "minAlpha = " + mMinAlpha + ", "
+                + "minFractionRendered = " + mMinFractionRendered + ", "
+                + "stabilityRequirementMs = " + mStabilityRequirementMs
                 + " }";
     }
 
     @Override
     @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeFloat(minAlpha);
-        dest.writeFloat(minFractionRendered);
-        dest.writeInt(stabilityRequirementMs);
+        dest.writeFloat(mMinAlpha);
+        dest.writeFloat(mMinFractionRendered);
+        dest.writeInt(mStabilityRequirementMs);
     }
 
     @Override
@@ -115,13 +135,34 @@
         return 0;
     }
 
+
+    @Override
+    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+    public int hashCode() {
+        return Objects.hash(mMinAlpha, mMinFractionRendered, mStabilityRequirementMs);
+    }
+
+    @Override
+    @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW)
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof TrustedPresentationThresholds that)) {
+            return false;
+        }
+        return mMinAlpha == that.mMinAlpha
+                && mMinFractionRendered == that.mMinFractionRendered
+                && mStabilityRequirementMs == that.mStabilityRequirementMs;
+    }
+
     /**
      * @hide
      */
     TrustedPresentationThresholds(@NonNull Parcel in) {
-        minAlpha = in.readFloat();
-        minFractionRendered = in.readFloat();
-        stabilityRequirementMs = in.readInt();
+        mMinAlpha = in.readFloat();
+        mMinFractionRendered = in.readFloat();
+        mStabilityRequirementMs = in.readInt();
 
         checkValid();
     }
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 069affb..3ffa274 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -20,14 +20,6 @@
 
 flag {
     namespace: "window_surfaces"
-    name: "get_host_token_api"
-    description: "Feature flag to associate the host and embedded windows"
-    is_fixed_read_only: true
-    bug: "304508760"
-}
-
-flag {
-    namespace: "window_surfaces"
     name: "transfer_gesture_to_embedded"
     description: "Enable public API for Window Surfaces"
     bug: "287076178"
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index ba87caa..5cb5963 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -40,6 +40,13 @@
             in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
             in HotwordDetectedResult result);
 
+    /**
+     * Called when the keyphrase is detected from audio coming from an external source.
+     *
+     * @param result Successful detection result payload.
+     */
+    void onKeyphraseDetectedFromExternalSource(in HotwordDetectedResult result);
+
    /**
      * Called when a generic sound trigger event is witnessed.
      *
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index ed943cb..eef6ce7 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -57,7 +57,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.LongArrayMultiStateCounter_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.LongArrayMultiStateCounter_host")
 public final class LongArrayMultiStateCounter implements Parcelable {
 
     /**
@@ -65,7 +65,7 @@
      */
     @android.ravenwood.annotation.RavenwoodKeepWholeClass
     @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-            "com.android.hoststubgen.nativesubstitution"
+            "com.android.platform.test.ravenwood.nativesubstitution"
             + ".LongArrayMultiStateCounter_host$LongArrayContainer_host")
     public static class LongArrayContainer {
         private static NativeAllocationRegistry sRegistry;
diff --git a/core/java/com/android/internal/os/LongMultiStateCounter.java b/core/java/com/android/internal/os/LongMultiStateCounter.java
index 064609f..e5662c7 100644
--- a/core/java/com/android/internal/os/LongMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongMultiStateCounter.java
@@ -57,7 +57,7 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.hoststubgen.nativesubstitution.LongMultiStateCounter_host")
+        "com.android.platform.test.ravenwood.nativesubstitution.LongMultiStateCounter_host")
 public final class LongMultiStateCounter implements Parcelable {
 
     private static NativeAllocationRegistry sRegistry;
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 6be553b..beffb9a 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -18,6 +18,7 @@
     // all of the 'license_kinds' from "frameworks_base_license"
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
+    default_team: "trendy_team_aaos_framework",
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4982f37..244fe30 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -618,7 +618,7 @@
      * @see #isMgf1DigestsSpecified()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
         if (mMgf1Digests.isEmpty()) {
             throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -633,7 +633,7 @@
      * @see #getMgf1Digests()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public boolean isMgf1DigestsSpecified() {
         return !mMgf1Digests.isEmpty();
     }
@@ -1292,7 +1292,7 @@
          * <p>See {@link KeyProperties}.{@code DIGEST} constants.
          */
         @NonNull
-        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
         public Builder setMgf1Digests(@NonNull @KeyProperties.DigestEnum String... mgf1Digests) {
             mMgf1Digests = Set.of(mgf1Digests);
             return this;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 7b6b2d1..2495d1a 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -401,7 +401,7 @@
      * @see #isMgf1DigestsSpecified()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
         if (mMgf1Digests.isEmpty()) {
             throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -416,7 +416,7 @@
      * @see #getMgf1Digests()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public boolean isMgf1DigestsSpecified() {
         return !mMgf1Digests.isEmpty();
     }
@@ -799,7 +799,7 @@
          * <p>See {@link KeyProperties}.{@code DIGEST} constants.
          */
         @NonNull
-        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
         public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
             mMgf1Digests = Set.of(mgf1Digests);
             return this;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 83ddfc5..e6c652c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -974,7 +974,7 @@
 
     private static boolean getMgf1DigestSetterFlag() {
         try {
-            return Flags.mgf1DigestSetter();
+            return Flags.mgf1DigestSetterV2();
         } catch (SecurityException e) {
             Log.w(TAG, "Cannot read MGF1 Digest setter flag value", e);
             return false;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 2d8c5a3..e6a63b9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -259,7 +259,7 @@
 
     private static boolean getMgf1DigestSetterFlag() {
         try {
-            return Flags.mgf1DigestSetter();
+            return Flags.mgf1DigestSetterV2();
         } catch (SecurityException e) {
             Log.w(NAME, "Cannot read MGF1 Digest setter flag value", e);
             return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
index fd91ac0..e1e41ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
@@ -58,7 +58,7 @@
             return false
         }
 
-        return controller.moveToDesktopWithoutDecor(taskId, WindowContainerTransaction())
+        return controller.moveToDesktop(taskId, WindowContainerTransaction())
     }
 
     override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 42c8d74..837cb99 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -244,47 +244,14 @@
     fun moveToDesktop(
             taskId: Int,
             wct: WindowContainerTransaction = WindowContainerTransaction()
-    ) {
+    ): Boolean {
         shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
             task -> moveToDesktop(task, wct)
-        }
-    }
-
-    /** Move a task with given `taskId` to desktop without decor */
-    fun moveToDesktopWithoutDecor(
-        taskId: Int,
-        wct: WindowContainerTransaction
-    ): Boolean {
-        val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: return false
-        moveToDesktopWithoutDecor(task, wct)
+        } ?: return false
         return true
     }
 
     /**
-     * Move a task to desktop without decor
-     */
-    private fun moveToDesktopWithoutDecor(
-        task: RunningTaskInfo,
-        wct: WindowContainerTransaction
-    ) {
-        KtProtoLog.v(
-            WM_SHELL_DESKTOP_MODE,
-            "DesktopTasksController: moveToDesktopWithoutDecor taskId=%d",
-            task.taskId
-        )
-        exitSplitIfApplicable(wct, task)
-        // Bring other apps to front first
-        bringDesktopAppsToFront(task.displayId, wct)
-        addMoveToDesktopChanges(wct, task)
-
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
-        } else {
-            shellTaskOrganizer.applyTransaction(wct)
-        }
-    }
-
-    /**
      * Move a task to desktop
      */
     fun moveToDesktop(
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4ee25c4..ac94a6f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
 import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
 
 import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -2213,6 +2214,18 @@
      */
     public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4;
 
+    /**
+     * Configure the codec with a detached output surface.
+     * <p>
+     * This flag is only defined for a video decoder. MediaCodec
+     * configured with this flag will be in Surface mode even though
+     * the surface parameter is null.
+     *
+     * @see detachOutputSurface
+     */
+    @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+    public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8;
+
     /** @hide */
     @IntDef(
         flag = true,
@@ -2395,6 +2408,31 @@
     private native void native_setSurface(@NonNull Surface surface);
 
     /**
+     *  Detach the current output surface of a codec.
+     *  <p>
+     *  Detaches the currently associated output Surface from the
+     *  MediaCodec decoder. This allows the SurfaceView or other
+     *  component holding the Surface to be safely destroyed or
+     *  modified without affecting the decoder's operation. After
+     *  calling this method (and after it returns), the decoder will
+     *  enter detached-Surface mode and will no longer render
+     *  output.
+     *
+     *  @throws IllegalStateException if the codec was not
+     *                                configured in surface mode.
+     *  @see CONFIGURE_FLAG_DETACHED_SURFACE
+     */
+    @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+    public void detachOutputSurface() {
+        if (!mHasSurface) {
+            throw new IllegalStateException("codec was not configured for an output surface");
+        }
+        // note: we still have a surface in detached mode, so keep mHasSurface
+        // we also technically allow calling detachOutputSurface multiple times in a row
+        // native_detachSurface();
+    }
+
+    /**
      * Create a persistent input surface that can be used with codecs that normally have an input
      * surface, such as video encoders. A persistent input can be reused by subsequent
      * {@link MediaCodec} or {@link MediaRecorder} instances, but can only be used by at
@@ -3212,6 +3250,51 @@
         }
     }
 
+    /**
+     * Similar to {@link #queueInputBuffers queueInputBuffers} but submits multiple access units
+     * in a buffer that is potentially encrypted.
+     * <strong>Check out further notes at {@link #queueInputBuffers queueInputBuffers}.</strong>
+     *
+     * @param index The index of a client-owned input buffer previously returned
+     *              in a call to {@link #dequeueInputBuffer}.
+     * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+     *                    contents in the buffer. The ArrayDeque and the BufferInfo objects provided
+     *                    can be recycled by the caller for re-use.
+     * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} objects to facilitate the
+     *                    decryption of the contents. The ArrayDeque and the CryptoInfo objects
+     *                    provided can be reused immediately after the call returns. These objects
+     *                    should correspond to bufferInfo objects to ensure correct decryption.
+     * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
+     * @throws MediaCodec.CodecException upon codec error.
+     * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+     *                    access units are not contiguous.
+     * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
+     *              An error code associated with the exception helps identify the
+     *              reason for the failure.
+     */
+    @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+    public final void queueSecureInputBuffers(
+            int index,
+            @NonNull ArrayDeque<BufferInfo> bufferInfos,
+            @NonNull ArrayDeque<CryptoInfo> cryptoInfos) {
+        synchronized(mBufferLock) {
+            if (mBufferMode == BUFFER_MODE_BLOCK) {
+                throw new IncompatibleWithBlockModelException("queueSecureInputBuffers() "
+                        + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+                        + "Please use getQueueRequest() to queue buffers");
+            }
+            invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
+            mDequeuedInputBuffers.remove(index);
+        }
+        try {
+            native_queueSecureInputBuffers(
+                    index, bufferInfos.toArray(), cryptoInfos.toArray());
+        } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
+            revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
+            throw e;
+        }
+    }
+
     private native final void native_queueSecureInputBuffer(
             int index,
             int offset,
@@ -3219,6 +3302,11 @@
             long presentationTimeUs,
             int flags) throws CryptoException;
 
+    private native final void native_queueSecureInputBuffers(
+            int index,
+            @NonNull Object[] bufferInfos,
+            @NonNull Object[] cryptoInfos) throws CryptoException, CodecException;
+
     /**
      * Returns the index of an input buffer to be filled with valid data
      * or -1 if no such buffer is currently available.
@@ -3464,7 +3552,7 @@
             mLinearBlock = block;
             mOffset = offset;
             mSize = size;
-            mCryptoInfo = null;
+            mCryptoInfos.clear();
             return this;
         }
 
@@ -3498,7 +3586,44 @@
             mLinearBlock = block;
             mOffset = offset;
             mSize = size;
-            mCryptoInfo = cryptoInfo;
+            mCryptoInfos.clear();
+            mCryptoInfos.add(cryptoInfo);
+            return this;
+        }
+
+        /**
+         * Set an encrypted linear block to this queue request. Exactly one buffer must be
+         * set for a queue request before calling {@link #queue}. The block can contain multiple
+         * access units and if present should be laid out contiguously and without gaps.
+         *
+         * @param block The linear block object
+         * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+         *                    contents in the buffer. The ArrayDeque and the BufferInfo objects
+         *                    provided can be recycled by the caller for re-use.
+         * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} that describes the
+         *                    structure of the encrypted input samples. The ArrayDeque and the
+         *                    BufferInfo objects provided can be recycled by the caller for re-use.
+         * @return this object
+         * @throws IllegalStateException if a buffer is already set
+         * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+         *                     access units are not contiguous.
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public @NonNull QueueRequest setMultiFrameEncryptedLinearBlock(
+                @NonNull LinearBlock block,
+                @NonNull ArrayDeque<MediaCodec.BufferInfo> bufferInfos,
+                @NonNull ArrayDeque<MediaCodec.CryptoInfo> cryptoInfos) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            if (mLinearBlock != null || mHardwareBuffer != null) {
+                throw new IllegalStateException("Cannot set block twice");
+            }
+            mLinearBlock = block;
+            mBufferInfos.clear();
+            mBufferInfos.addAll(bufferInfos);
+            mCryptoInfos.clear();
+            mCryptoInfos.addAll(cryptoInfos);
             return this;
         }
 
@@ -3710,8 +3835,10 @@
                 mBufferInfos.add(info);
             }
             if (mLinearBlock != null) {
+
                 mCodec.native_queueLinearBlock(
-                        mIndex, mLinearBlock, mCryptoInfo,
+                        mIndex, mLinearBlock,
+                        mCryptoInfos.isEmpty() ? null : mCryptoInfos.toArray(),
                         mBufferInfos.toArray(),
                         mTuningKeys, mTuningValues);
             } else if (mHardwareBuffer != null) {
@@ -3726,11 +3853,11 @@
             mLinearBlock = null;
             mOffset = 0;
             mSize = 0;
-            mCryptoInfo = null;
             mHardwareBuffer = null;
             mPresentationTimeUs = 0;
             mFlags = 0;
             mBufferInfos.clear();
+            mCryptoInfos.clear();
             mTuningKeys.clear();
             mTuningValues.clear();
             return this;
@@ -3750,11 +3877,11 @@
         private LinearBlock mLinearBlock = null;
         private int mOffset = 0;
         private int mSize = 0;
-        private MediaCodec.CryptoInfo mCryptoInfo = null;
         private HardwareBuffer mHardwareBuffer = null;
         private long mPresentationTimeUs = 0;
         private @BufferFlag int mFlags = 0;
         private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
+        private final ArrayDeque<CryptoInfo> mCryptoInfos = new ArrayDeque<>();
         private final ArrayList<String> mTuningKeys = new ArrayList<>();
         private final ArrayList<Object> mTuningValues = new ArrayList<>();
 
@@ -3764,7 +3891,7 @@
     private native void native_queueLinearBlock(
             int index,
             @NonNull LinearBlock block,
-            @Nullable CryptoInfo cryptoInfo,
+            @Nullable Object[] cryptoInfos,
             @NonNull Object[] bufferInfos,
             @NonNull ArrayList<String> keys,
             @NonNull ArrayList<Object> values);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 86f89ab..3174c37 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -20,6 +20,7 @@
 import static android.media.Utils.sortDistinctRanges;
 import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
 import static android.media.codec.Flags.FLAG_HLG_EDITING;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
 import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
 
 import android.annotation.FlaggedApi;
@@ -778,6 +779,17 @@
         public static final String FEATURE_Roi = "region-of-interest";
 
         /**
+         * <b>video decoder only</b>: codec supports detaching the
+         * output surface when in Surface mode.
+         * <p> If true, the codec can be configured in Surface mode
+         * without an actual surface (in detached surface mode).
+         * @see MediaCodec#CONFIGURE_FLAG_DETACHED_SURFACE
+         */
+        @SuppressLint("AllUpper")
+        @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+        public static final String FEATURE_DetachedSurface = "detached-surface";
+
+        /**
          * Query codec feature capabilities.
          * <p>
          * These features are supported to be used by the codec.  These
@@ -814,6 +826,9 @@
                 if (android.media.codec.Flags.dynamicColorAspects()) {
                     features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));
                 }
+                if (android.media.codec.Flags.nullOutputSurface()) {
+                    features.add(new Feature(FEATURE_DetachedSurface,     (1 << 9), true));
+                }
 
                 // feature to exclude codec from REGULAR codec list
                 features.add(new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true));
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 7fa3ed6..144b01a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -1017,7 +1017,8 @@
         updateRoutesOnHandler(currentRoutes);
 
         RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo();
-        mSystemController.setRoutingSessionInfo(currentSystemSessionInfo);
+        mSystemController.setRoutingSessionInfo(ensureClientPackageNameForSystemSession(
+                currentSystemSessionInfo, mContext.getPackageName()));
         if (!oldInfo.equals(currentSystemSessionInfo)) {
             notifyControllerUpdated(mSystemController);
         }
@@ -1440,6 +1441,25 @@
         }
     }
 
+    /**
+     * Sets the routing session's {@linkplain RoutingSessionInfo#getClientPackageName() client
+     * package name} to {@code packageName} if empty and returns the session.
+     *
+     * <p>This method must only be used for {@linkplain RoutingSessionInfo#isSystemSession()
+     * system routing sessions}.
+     */
+    private static RoutingSessionInfo ensureClientPackageNameForSystemSession(
+            @NonNull RoutingSessionInfo sessionInfo, @NonNull String packageName) {
+        if (!sessionInfo.isSystemSession()
+                || !TextUtils.isEmpty(sessionInfo.getClientPackageName())) {
+            return sessionInfo;
+        }
+
+        return new RoutingSessionInfo.Builder(sessionInfo)
+                .setClientPackageName(packageName)
+                .build();
+    }
+
     /** Callback for receiving events about media route discovery. */
     public abstract static class RouteCallback {
         /**
@@ -2891,25 +2911,6 @@
         }
 
         /**
-         * Sets the routing session's {@linkplain RoutingSessionInfo#getClientPackageName() client
-         * package name} to {@link #mClientPackageName} if empty and returns the session.
-         *
-         * <p>This method must only be used for {@linkplain RoutingSessionInfo#isSystemSession()
-         * system routing sessions}.
-         */
-        private RoutingSessionInfo ensureClientPackageNameForSystemSession(
-                RoutingSessionInfo sessionInfo) {
-            if (!sessionInfo.isSystemSession()
-                    || !TextUtils.isEmpty(sessionInfo.getClientPackageName())) {
-                return sessionInfo;
-            }
-
-            return new RoutingSessionInfo.Builder(sessionInfo)
-                    .setClientPackageName(mClientPackageName)
-                    .build();
-        }
-
-        /**
          * Requests the release of a {@linkplain RoutingSessionInfo routing session}. Calls {@link
          * #onSessionReleasedOnHandler(RoutingSessionInfo)} on success.
          *
@@ -2997,7 +2998,7 @@
             RoutingController oldController;
             if (oldSession.isSystemSession()) {
                 mSystemController.setRoutingSessionInfo(
-                        ensureClientPackageNameForSystemSession(oldSession));
+                        ensureClientPackageNameForSystemSession(oldSession, mClientPackageName));
                 oldController = mSystemController;
             } else {
                 oldController = new RoutingController(oldSession);
@@ -3006,7 +3007,7 @@
             RoutingController newController;
             if (newSession.isSystemSession()) {
                 mSystemController.setRoutingSessionInfo(
-                        ensureClientPackageNameForSystemSession(newSession));
+                        ensureClientPackageNameForSystemSession(newSession, mClientPackageName));
                 newController = mSystemController;
             } else {
                 newController = new RoutingController(newSession);
@@ -3033,7 +3034,7 @@
             RoutingController controller;
             if (session.isSystemSession()) {
                 mSystemController.setRoutingSessionInfo(
-                        ensureClientPackageNameForSystemSession(session));
+                        ensureClientPackageNameForSystemSession(session, mClientPackageName));
                 controller = mSystemController;
             } else {
                 controller = new RoutingController(session);
@@ -3303,7 +3304,8 @@
         public RoutingSessionInfo getSystemSessionInfo() {
             RoutingSessionInfo currentSystemSessionInfo = null;
             try {
-                currentSystemSessionInfo = mMediaRouterService.getSystemSessionInfo();
+                currentSystemSessionInfo = ensureClientPackageNameForSystemSession(
+                        mMediaRouterService.getSystemSessionInfo(), mContext.getPackageName());
             } catch (RemoteException ex) {
                 ex.rethrowFromSystemServer();
             }
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 8cdd59e..8396005 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -458,6 +458,24 @@
             presentationTimeUs, flags, errorDetailMsg);
 }
 
+status_t JMediaCodec::queueSecureInputBuffers(
+        size_t index,
+        size_t offset,
+        size_t size,
+        const sp<RefBase> &auInfos_,
+        const sp<RefBase> &cryptoInfos_,
+        AString *errorDetailMsg) {
+    sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
+    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
+    return mCodec->queueSecureInputBuffers(
+            index,
+            offset,
+            size,
+            auInfos,
+            cryptoInfos,
+            errorDetailMsg);
+}
+
 status_t JMediaCodec::queueBuffer(
         size_t index, const std::shared_ptr<C2Buffer> &buffer,
         const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
@@ -470,19 +488,16 @@
         size_t index,
         const sp<hardware::HidlMemory> &buffer,
         size_t offset,
-        const CryptoPlugin::SubSample *subSamples,
-        size_t numSubSamples,
-        const uint8_t key[16],
-        const uint8_t iv[16],
-        CryptoPlugin::Mode mode,
-        const CryptoPlugin::Pattern &pattern,
+        size_t size,
         const sp<RefBase> &infos,
+        const sp<RefBase> &cryptoInfos_,
         const sp<AMessage> &tunings,
         AString *errorDetailMsg) {
     sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
+    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
     return mCodec->queueEncryptedBuffer(
-            index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
-            auInfo, tunings, errorDetailMsg);
+            index, buffer, offset, size, auInfo, cryptoInfos,
+            tunings, errorDetailMsg);
 }
 
 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -2262,6 +2277,61 @@
     CryptoPlugin::Pattern mPattern;
 };
 
+// This class takes away all dependencies on java(env and jni) and
+// could be used for taking cryptoInfo objects to MediaCodec.
+struct MediaCodecCryptoInfo: public CodecCryptoInfo {
+    explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
+        if (cryptoInfo.mErr == OK) {
+            mNumSubSamples = cryptoInfo.mNumSubSamples;
+            mMode = cryptoInfo.mMode;
+            mPattern = cryptoInfo.mPattern;
+            if (cryptoInfo.mKey != nullptr) {
+                mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
+                mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
+            }
+            if (cryptoInfo.mIv != nullptr) {
+               mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
+               mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
+            }
+            if (cryptoInfo.mSubSamples != nullptr) {
+                mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
+                if (mSubSamplesBuffer.get()) {
+                    CryptoPlugin::SubSample * samples =
+                            (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+                    for (int s = 0 ; s < mNumSubSamples ; s++) {
+                        samples[s].mNumBytesOfClearData =
+                                cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
+                        samples[s].mNumBytesOfEncryptedData =
+                                cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
+                    }
+                    mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+                }
+            }
+
+        }
+    }
+
+    explicit MediaCodecCryptoInfo(jint size) {
+        mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
+        mNumSubSamples = 1;
+        if (mSubSamplesBuffer.get()) {
+            CryptoPlugin::SubSample * samples =
+                    (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+            samples[0].mNumBytesOfClearData = size;
+            samples[0].mNumBytesOfEncryptedData = 0;
+            mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+        }
+    }
+    ~MediaCodecCryptoInfo() {}
+
+protected:
+    // all backup buffers for the base object.
+    sp<ABuffer> mKeyBuffer;
+    sp<ABuffer> mIvBuffer;
+    sp<ABuffer> mSubSamplesBuffer;
+
+};
+
 static void android_media_MediaCodec_queueSecureInputBuffer(
         JNIEnv *env,
         jobject thiz,
@@ -2430,6 +2500,99 @@
             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
 }
 
+static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
+        jint * const totalSize,
+        std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
+        const jobjectArray &objArray,
+        AString * const errorDetailMsg) {
+    if (env == nullptr
+            || cryptoInfoObjs == nullptr
+            || totalSize == nullptr) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+        }
+        return BAD_VALUE;
+    }
+    const jsize numEntries = env->GetArrayLength(objArray);
+    if (numEntries <= 0) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
+        }
+        return BAD_VALUE;
+    }
+    cryptoInfoObjs->clear();
+    *totalSize = 0;
+    jint size = 0;
+    for (jsize i = 0; i < numEntries ; i++) {
+        jobject param = env->GetObjectArrayElement(objArray, i);
+        if (param == NULL) {
+            if (errorDetailMsg) {
+                *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+            }
+            return BAD_VALUE;
+        }
+        NativeCryptoInfo nativeInfo(env, param);
+        std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
+        for (int i = 0; i < info->mNumSubSamples; i++) {
+            size += info->mSubSamples[i].mNumBytesOfClearData;
+            size += info->mSubSamples[i].mNumBytesOfEncryptedData;
+        }
+        cryptoInfoObjs->push_back(std::move(info));
+    }
+    *totalSize = size;
+    return OK;
+}
+
+
+static void android_media_MediaCodec_queueSecureInputBuffers(
+        JNIEnv *env,
+        jobject thiz,
+        jint index,
+        jobjectArray bufferInfosObjs,
+        jobjectArray cryptoInfoObjs) {
+    ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL || codec->initCheck() != OK) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+        return;
+    }
+    sp<BufferInfosWrapper> auInfos =
+            new BufferInfosWrapper{decltype(auInfos->value)()};
+    sp<CryptoInfosWrapper> cryptoInfos =
+        new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+    AString errorDetailMsg;
+    jint initialOffset = 0;
+    jint totalSize = 0;
+    status_t err = extractInfosFromObject(
+            env,
+            &initialOffset,
+            &totalSize,
+            &auInfos->value,
+            bufferInfosObjs,
+            &errorDetailMsg);
+    if (err == OK) {
+        err = extractCryptoInfosFromObjectArray(env,
+            &totalSize,
+            &cryptoInfos->value,
+            cryptoInfoObjs,
+            &errorDetailMsg);
+    }
+    if (err == OK) {
+        err = codec->queueSecureInputBuffers(
+                index,
+                initialOffset,
+                totalSize,
+                auInfos,
+                cryptoInfos,
+                &errorDetailMsg);
+    }
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
+}
+
 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
     ALOGV("android_media_MediaCodec_mapHardwareBuffer");
     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
@@ -2762,7 +2925,7 @@
 
 static void android_media_MediaCodec_native_queueLinearBlock(
         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
-        jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
+        jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
     ALOGV("android_media_MediaCodec_native_queueLinearBlock");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2780,8 +2943,8 @@
                 "error occurred while converting tunings from Java to native");
         return;
     }
-    jint totalSize;
-    jint initialOffset;
+    jint totalSize = 0;
+    jint initialOffset = 0;
     std::vector<AccessUnitInfo> infoVec;
     AString errorDetailMsg;
     err = extractInfosFromObject(env,
@@ -2832,8 +2995,19 @@
                     "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
-        auto cryptoInfo =
-                cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
+        sp<CryptoInfosWrapper> cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+        jint sampleSize = 0;
+        if (cryptoInfoArray != nullptr) {
+            extractCryptoInfosFromObjectArray(env,
+                    &sampleSize,
+                    &cryptoInfos->value,
+                    cryptoInfoArray,
+                    &errorDetailMsg);
+        } else {
+            sampleSize = totalSize;
+            std::unique_ptr<CodecCryptoInfo> cryptoInfo{new MediaCodecCryptoInfo(totalSize)};
+            cryptoInfos->value.push_back(std::move(cryptoInfo));
+        }
         if (env->ExceptionCheck()) {
             // Creation of cryptoInfo failed. Let the exception bubble up.
             return;
@@ -2842,11 +3016,9 @@
                 index,
                 memory,
                 initialOffset,
-                cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
-                (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
-                cryptoInfo.mMode,
-                cryptoInfo.mPattern,
+                sampleSize,
                 infos,
+                cryptoInfos,
                 tunings,
                 &errorDetailMsg);
         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -3950,6 +4122,9 @@
     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
       (void *)android_media_MediaCodec_queueSecureInputBuffer },
 
+    { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
+      (void *)android_media_MediaCodec_queueSecureInputBuffers },
+
     { "native_mapHardwareBuffer",
       "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
       (void *)android_media_MediaCodec_mapHardwareBuffer },
@@ -3957,7 +4132,7 @@
     { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
 
     { "native_queueLinearBlock",
-      "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
+      "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
       "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
       (void *)android_media_MediaCodec_native_queueLinearBlock },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 02708ef..abb23f5 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -114,6 +114,14 @@
             uint32_t flags,
             AString *errorDetailMsg);
 
+    status_t queueSecureInputBuffers(
+            size_t index,
+            size_t offset,
+            size_t size,
+            const sp<RefBase> &auInfos,
+            const sp<RefBase> &cryptoInfos,
+            AString *errorDetailMsg);
+
     status_t queueBuffer(
             size_t index, const std::shared_ptr<C2Buffer> &buffer,
             const sp<RefBase> &infos, const sp<AMessage> &tunings,
@@ -123,13 +131,9 @@
             size_t index,
             const sp<hardware::HidlMemory> &buffer,
             size_t offset,
-            const CryptoPlugin::SubSample *subSamples,
-            size_t numSubSamples,
-            const uint8_t key[16],
-            const uint8_t iv[16],
-            CryptoPlugin::Mode mode,
-            const CryptoPlugin::Pattern &pattern,
+            size_t size,
             const sp<RefBase> &infos,
+            const sp<RefBase> &cryptoInfos,
             const sp<AMessage> &tunings,
             AString *errorDetailMsg);
 
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 64e8efe..6efb028 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -314,6 +314,23 @@
     return event;
 }
 
+jobject AInputEvent_toJava(JNIEnv* env, const AInputEvent* aInputEvent) {
+    LOG_ALWAYS_FATAL_IF(aInputEvent == nullptr, "Expected aInputEvent to be non-null");
+    const int32_t eventType = AInputEvent_getType(aInputEvent);
+    switch (eventType) {
+        case AINPUT_EVENT_TYPE_MOTION:
+            return android::android_view_MotionEvent_obtainAsCopy(env,
+                                                                  static_cast<const MotionEvent&>(
+                                                                          *aInputEvent));
+        case AINPUT_EVENT_TYPE_KEY:
+            return android::android_view_KeyEvent_fromNative(env,
+                                                             static_cast<const KeyEvent&>(
+                                                                     *aInputEvent));
+        default:
+            LOG_ALWAYS_FATAL("Unexpected event type %d in AInputEvent_toJava.", eventType);
+    }
+}
+
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
         int ident, ALooper_callbackFunc callback, void* data) {
     InputQueue* iq = static_cast<InputQueue*>(queue);
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 9605108..3302265 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -90,6 +90,7 @@
     AInputEvent_getSource;
     AInputEvent_getType;
     AInputEvent_release; # introduced=31
+    AInputEvent_toJava; # introduced=35
     AInputQueue_attachLooper;
     AInputQueue_detachLooper;
     AInputQueue_finishEvent;
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index f9dd04b..0728daf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -40,7 +40,6 @@
 ): Modifier {
     val translationX by viewModel.translationX(params).collectAsState(initial = 0f)
     val translationY by viewModel.translationY(params).collectAsState(initial = 0f)
-    val alpha by viewModel.alpha.collectAsState(initial = 1f)
     val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel())
 
     return this.graphicsLayer {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 0b320a2..ef2b6f0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -27,7 +27,10 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -56,11 +59,10 @@
     private val testScope = kosmos.testScope
     private val repository by lazy { kosmos.fakeKeyguardRepository }
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
-    private val commandQueue by lazy {
-        FakeCommandQueue()
-    }
+    private val commandQueue by lazy { FakeCommandQueue() }
     private val bouncerRepository = FakeKeyguardBouncerRepository()
     private val shadeRepository = FakeShadeRepository()
+    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val transitionState: MutableStateFlow<ObservableTransitionState> =
         MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
 
@@ -73,6 +75,7 @@
             bouncerRepository = bouncerRepository,
             configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),
             shadeRepository = shadeRepository,
+            keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
             sceneInteractorProvider = { sceneInteractor },
         )
     }
@@ -188,6 +191,49 @@
         }
 
     @Test
+    fun dismissAlpha() =
+        testScope.runTest {
+            val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.LOCKSCREEN,
+                testScope,
+            )
+
+            repository.setStatusBarState(StatusBarState.KEYGUARD)
+            shadeRepository.setLegacyShadeExpansion(1f)
+
+            // When not dismissable, no alpha value (null) should emit
+            repository.setKeyguardDismissible(false)
+            assertThat(dismissAlpha).isNull()
+
+            repository.setKeyguardDismissible(true)
+            assertThat(dismissAlpha).isGreaterThan(0.95f)
+        }
+
+    @Test
+    fun dismissAlpha_whenShadeIsExpandedEmitsNull() =
+        testScope.runTest {
+            val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.LOCKSCREEN,
+                testScope,
+            )
+
+            repository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+            shadeRepository.setQsExpansion(1f)
+
+            repository.setKeyguardDismissible(false)
+            assertThat(dismissAlpha).isNull()
+
+            repository.setKeyguardDismissible(true)
+            assertThat(dismissAlpha).isNull()
+        }
+
+    @Test
     fun animationDozingTransitions() =
         testScope.runTest {
             kosmos.fakeSceneContainerFlags.enabled = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
index 83782e2..837a9db 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
@@ -25,6 +25,8 @@
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.whenever
@@ -42,49 +44,69 @@
 @RunWith(AndroidJUnit4::class)
 class AodAlphaViewModelTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var occludedToLockscreenTransitionViewModel:
-        OccludedToLockscreenTransitionViewModel
+    @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val keyguardRepository = kosmos.fakeKeyguardRepository
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    private val occludedToLockscreenAlpha = MutableStateFlow(0f)
 
     private lateinit var underTest: AodAlphaViewModel
 
+    private val enterFromTopAnimationAlpha = MutableStateFlow(0f)
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        whenever(occludedToLockscreenTransitionViewModel.lockscreenAlpha)
-            .thenReturn(occludedToLockscreenAlpha)
-        kosmos.occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel
+        whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha)
+            .thenReturn(enterFromTopAnimationAlpha)
+        kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
 
         underTest = kosmos.aodAlphaViewModel
     }
 
     @Test
-    fun alpha() =
+    fun alpha_WhenGoneToAod() =
         testScope.runTest {
             val alpha by collectLastValue(underTest.alpha)
 
             keyguardTransitionRepository.sendTransitionSteps(
-                from = KeyguardState.OFF,
-                to = KeyguardState.LOCKSCREEN,
+                from = KeyguardState.AOD,
+                to = KeyguardState.GONE,
                 testScope = testScope,
             )
-
-            keyguardRepository.setKeyguardAlpha(0.1f)
-            assertThat(alpha).isEqualTo(0.1f)
-            keyguardRepository.setKeyguardAlpha(0.5f)
-            assertThat(alpha).isEqualTo(0.5f)
-            keyguardRepository.setKeyguardAlpha(0.2f)
-            assertThat(alpha).isEqualTo(0.2f)
-            keyguardRepository.setKeyguardAlpha(0f)
             assertThat(alpha).isEqualTo(0f)
-            occludedToLockscreenAlpha.value = 0.8f
-            assertThat(alpha).isEqualTo(0.8f)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.GONE,
+                to = KeyguardState.AOD,
+                testScope = testScope,
+            )
+            enterFromTopAnimationAlpha.value = 0.5f
+            assertThat(alpha).isEqualTo(0.5f)
+
+            enterFromTopAnimationAlpha.value = 1f
+            assertThat(alpha).isEqualTo(1f)
+        }
+
+    @Test
+    fun alpha_WhenGoneToDozing() =
+        testScope.runTest {
+            val alpha by collectLastValue(underTest.alpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.GONE,
+                testScope = testScope,
+            )
+            assertThat(alpha).isEqualTo(0f)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.GONE,
+                to = KeyguardState.DOZING,
+                testScope = testScope,
+            )
+            assertThat(alpha).isEqualTo(1f)
         }
 
     @Test
@@ -92,17 +114,53 @@
         testScope.runTest {
             val alpha by collectLastValue(underTest.alpha)
 
-            keyguardTransitionRepository.sendTransitionSteps(
-                from = KeyguardState.LOCKSCREEN,
-                to = KeyguardState.GONE,
-                testScope = testScope,
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.STARTED,
+                )
+            )
+            assertThat(alpha).isNull()
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.RUNNING,
+                    value = 0.5f,
+                )
+            )
+            assertThat(alpha).isNull()
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.GONE,
+                    transitionState = TransitionState.RUNNING,
+                    value = 1f,
+                )
+            )
+            assertThat(alpha).isEqualTo(0f)
+        }
+
+    @Test
+    fun enterFromTopAlpha() =
+        testScope.runTest {
+            val alpha by collectLastValue(underTest.alpha)
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
+                )
             )
 
-            keyguardRepository.setKeyguardAlpha(0.1f)
-            assertThat(alpha).isEqualTo(0f)
-            keyguardRepository.setKeyguardAlpha(0.5f)
-            assertThat(alpha).isEqualTo(0f)
-            keyguardRepository.setKeyguardAlpha(1f)
-            assertThat(alpha).isEqualTo(0f)
+            enterFromTopAnimationAlpha.value = 0.2f
+            assertThat(alpha).isEqualTo(0.2f)
+
+            enterFromTopAnimationAlpha.value = 1f
+            assertThat(alpha).isEqualTo(1f)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index d52696a..74fa465 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -65,7 +65,6 @@
             clockControllerProvider = { clockController },
         )
     private val burnInFlow = MutableStateFlow(BurnInModel())
-    private val enterFromTopAnimationAlpha = MutableStateFlow(0f)
 
     @Before
     fun setUp() {
@@ -74,8 +73,6 @@
         MockitoAnnotations.initMocks(this)
         whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow)
         kosmos.burnInInteractor = burnInInteractor
-        whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha)
-            .thenReturn(enterFromTopAnimationAlpha)
         whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
             .thenReturn(emptyFlow())
         kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
@@ -278,16 +275,4 @@
             assertThat(translationY).isEqualTo(0)
             assertThat(scale).isEqualTo(BurnInScaleViewModel(scale = 0.5f, scaleClockOnly = false))
         }
-
-    @Test
-    fun alpha() =
-        testScope.runTest {
-            val alpha by collectLastValue(underTest.alpha)
-
-            enterFromTopAnimationAlpha.value = 0.2f
-            assertThat(alpha).isEqualTo(0.2f)
-
-            enterFromTopAnimationAlpha.value = 1f
-            assertThat(alpha).isEqualTo(1f)
-        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index bf1d76f..e04cbfd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -255,14 +255,21 @@
         testScope.runTest {
             val alpha by collectLastValue(underTest.alpha(viewState))
 
+            // Default value check
+            assertThat(alpha).isEqualTo(1f)
+
             // Hub transition state is idle with hub open.
             communalRepository.setTransitionState(
                 flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
             )
             runCurrent()
 
-            // Set keyguard alpha to 1.0f.
-            keyguardInteractor.setAlpha(1.0f)
+            // Run at least 1 transition to make sure value remains at 0
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.LOCKSCREEN,
+                testScope,
+            )
 
             // Alpha property remains 0 regardless.
             assertThat(alpha).isEqualTo(0f)
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 91e6b62..ee260e1 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -421,9 +421,11 @@
         smallTimeListener?.update(shouldTimeListenerRun)
         largeTimeListener?.update(shouldTimeListenerRun)
 
-        // Query ZenMode data
-        zenModeCallback.onZenChanged(zenModeController.zen)
-        zenModeCallback.onNextAlarmChanged()
+        bgExecutor.execute {
+            // Query ZenMode data
+            zenModeCallback.onZenChanged(zenModeController.zen)
+            zenModeCallback.onNextAlarmChanged()
+        }
     }
 
     fun unregisterListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b5ca79e7..63fd608 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -690,18 +690,17 @@
                             } else {
                                 resetStateLocked();
                             }
-                        } else {
-                            if (lastSimStateWasLocked && mShowing) {
-                                if (DEBUG_SIM_STATES) {
-                                    Log.d(TAG, "SIM moved to "
-                                            + "NOT_READY/ABSENT/UNKNOWN when the previous state "
-                                            + "was locked. Reset the state.");
-                                }
+                        }
+                        if (simState == TelephonyManager.SIM_STATE_ABSENT) {
+                            // MVNO SIMs can become transiently NOT_READY when switching networks,
+                            // so we should only lock when they are ABSENT.
+                            if (lastSimStateWasLocked) {
+                                if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+                                        + "previous state was locked. Reset the state.");
                                 resetStateLocked();
                             }
+                            mSimWasLocked.append(slotId, false);
                         }
-
-                        mSimWasLocked.append(slotId, false);
                     }
                     break;
                 case TelephonyManager.SIM_STATE_PIN_REQUIRED:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index e20f570..7593ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -150,6 +150,7 @@
                 when (toState) {
                     KeyguardState.DREAMING -> TO_DREAMING_DURATION
                     KeyguardState.AOD -> TO_AOD_DURATION
+                    KeyguardState.DOZING -> TO_DOZING_DURATION
                     KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
                     else -> DEFAULT_DURATION
                 }.inWholeMilliseconds
@@ -160,6 +161,7 @@
         private val DEFAULT_DURATION = 500.milliseconds
         val TO_DREAMING_DURATION = 933.milliseconds
         val TO_AOD_DURATION = 1300.milliseconds
+        val TO_DOZING_DURATION = 933.milliseconds
         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 1da0a0e..57e9ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
+import android.util.MathUtils
 import com.android.app.animation.Interpolators
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.dagger.SysUISingleton
@@ -208,7 +209,10 @@
                                     }
                                 transitionRepository.updateTransition(
                                     id,
-                                    1f - shadeExpansion,
+                                    // This maps the shadeExpansion to a much faster curve, to match
+                                    // the existing logic
+                                    1f -
+                                        MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, shadeExpansion),
                                     nextState,
                                 )
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 22d11d0..405d1d4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.res.R
@@ -79,6 +80,7 @@
     bouncerRepository: KeyguardBouncerRepository,
     configurationInteractor: ConfigurationInteractor,
     shadeRepository: ShadeRepository,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
     sceneInteractorProvider: Provider<SceneInteractor>,
 ) {
     // TODO(b/296118689): move to a repository
@@ -233,8 +235,33 @@
     /** The position of the keyguard clock. */
     val clockPosition: Flow<Position> = repository.clockPosition
 
+    @Deprecated("Use the relevant TransitionViewModel")
     val keyguardAlpha: Flow<Float> = repository.keyguardAlpha
 
+    /**
+     * When the lockscreen can be dismissed, emit an alpha value as the user swipes up. This is
+     * useful just before the code commits to moving to GONE.
+     */
+    val dismissAlpha: Flow<Float?> =
+        combine(
+                shadeRepository.legacyShadeExpansion,
+                statusBarState,
+                keyguardTransitionInteractor.currentKeyguardState,
+                isKeyguardDismissible,
+            ) { legacyShadeExpansion, statusBarState, currentKeyguardState, isKeyguardDismissible ->
+                if (
+                    statusBarState == StatusBarState.KEYGUARD &&
+                        isKeyguardDismissible &&
+                        currentKeyguardState == LOCKSCREEN
+                ) {
+                    MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, legacyShadeExpansion)
+                } else {
+                    null
+                }
+            }
+            .onStart { emit(null) }
+            .distinctUntilChanged()
+
     val keyguardTranslationY: Flow<Float> =
         configurationInteractor
             .dimensionPixelSize(R.dimen.keyguard_translate_distance_on_swipe_up)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 310f13d..d1fd719 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -56,7 +56,6 @@
 constructor(
     @Application val scope: CoroutineScope,
     private val repository: KeyguardTransitionRepository,
-    private val keyguardInteractor: dagger.Lazy<KeyguardInteractor>,
     private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>,
     private val fromPrimaryBouncerTransitionInteractor:
         dagger.Lazy<FromPrimaryBouncerTransitionInteractor>,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 1b7a507..5604ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -179,7 +179,7 @@
                         }
 
                         launch {
-                            viewModel.lockscreenStateAlpha.collect { alpha ->
+                            viewModel.lockscreenStateAlpha(viewState).collect { alpha ->
                                 childViews[statusViewId]?.alpha = alpha
                             }
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
index d4ea728..f208e85 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
@@ -19,15 +19,15 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.combineTransform
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
 
 /** Models UI state for the alpha of the AOD (always-on display). */
@@ -35,27 +35,28 @@
 class AodAlphaViewModel
 @Inject
 constructor(
-    keyguardInteractor: KeyguardInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
-    occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+    goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+    goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
 ) {
 
     /** The alpha level for the entire lockscreen while in AOD. */
     val alpha: Flow<Float> =
-        combine(
-                keyguardTransitionInteractor.transitionValue(KeyguardState.GONE).onStart {
-                    emit(0f)
-                },
-                merge(
-                    keyguardInteractor.keyguardAlpha,
-                    occludedToLockscreenTransitionViewModel.lockscreenAlpha,
-                )
-            ) { transitionToGone, alpha ->
-                if (transitionToGone == 1f) {
-                    // Ensures content is not visible when in GONE state
-                    0f
-                } else {
-                    alpha
+        combineTransform(
+                keyguardTransitionInteractor.transitions,
+                goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
+                goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
+            ) { step, goneToAodAlpha, goneToDozingAlpha ->
+                if (step.to == GONE) {
+                    // When transitioning to GONE, only emit a value when complete as other
+                    // transitions may be controlling the alpha fade
+                    if (step.value == 1f) {
+                        emit(0f)
+                    }
+                } else if (step.from == GONE && step.to == AOD) {
+                    emit(goneToAodAlpha)
+                } else if (step.from == GONE && step.to == DOZING) {
+                    emit(goneToDozingAlpha)
                 }
             }
             .distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 8110de2..6fcbf48 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
@@ -66,9 +67,6 @@
     private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
     private val keyguardClockViewModel: KeyguardClockViewModel,
 ) {
-    /** Alpha for elements that appear and move during the animation -> AOD */
-    val alpha: Flow<Float> = goneToAodTransitionViewModel.enterFromTopAnimationAlpha
-
     /** Horizontal translation for elements that need to apply anti-burn-in tactics. */
     fun translationX(
         params: BurnInParameters,
@@ -131,6 +129,9 @@
         return combine(
             merge(
                     keyguardTransitionInteractor.transition(GONE, AOD).map { it.value },
+                    keyguardTransitionInteractor.transition(AOD, PRIMARY_BOUNCER).map {
+                        1f - it.value
+                    },
                     keyguardTransitionInteractor.transition(ALTERNATE_BOUNCER, AOD).map {
                         it.value
                     },
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
index 3a98359..a3888c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
@@ -57,21 +57,32 @@
         var startValue = 0f
         return transitionAnimation.sharedFlowWithState(
             duration = 500.milliseconds,
-            onStart = {
-                startValue = currentTranslationY() ?: 0f
-                startValue
-            },
+            onStart = { startValue = currentTranslationY() ?: 0f },
             onStep = { MathUtils.lerp(startValue, 0f, FAST_OUT_SLOW_IN.getInterpolation(it)) },
         )
     }
 
     /** Ensure alpha is set to be visible */
-    val lockscreenAlpha: Flow<Float> =
-        transitionAnimation.sharedFlow(
+    fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+        var startAlpha: Float? = null
+        return transitionAnimation.sharedFlow(
             duration = 500.milliseconds,
-            onStart = { 1f },
-            onStep = { 1f },
+            onStep = {
+                if (startAlpha == null) {
+                    startAlpha = viewState.alpha()
+                }
+                MathUtils.lerp(startAlpha!!, 1f, it)
+            },
+            onFinish = {
+                startAlpha = null
+                1f
+            },
+            onCancel = {
+                startAlpha = null
+                1f
+            },
         )
+    }
 
     val shortcutsAlpha: Flow<Float> =
         transitionAnimation.sharedFlow(
@@ -88,5 +99,10 @@
             onFinish = { 1f },
         )
 
-    override val deviceEntryParentViewAlpha: Flow<Float> = lockscreenAlpha
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 500.milliseconds,
+            onStart = { 1f },
+            onStep = { 1f },
+        )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
index e4610c1..f81941b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
@@ -50,6 +50,8 @@
             onCancel = { 0f },
         )
 
+    val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(1f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..55a289e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
@@ -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.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DOZING_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/** Breaks down GONE->DOZING transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class GoneToDozingTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+) {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_DOZING_DURATION,
+            from = KeyguardState.GONE,
+            to = KeyguardState.DOZING,
+        )
+
+    val lockscreenAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 500.milliseconds,
+            onStep = { 0f },
+            onCancel = { 1f },
+            onFinish = { 1f },
+        )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 83be651..f790d35 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -48,6 +48,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
@@ -63,15 +64,25 @@
     private val communalInteractor: CommunalInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
-    private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
-    private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
     private val alternateBouncerToGoneTransitionViewModel:
         AlternateBouncerToGoneTransitionViewModel,
-    private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
-    private val lockscreenToGlanceableHubTransitionViewModel:
-        LockscreenToGlanceableHubTransitionViewModel,
+    private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+    private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
     private val glanceableHubToLockscreenTransitionViewModel:
         GlanceableHubToLockscreenTransitionViewModel,
+    private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
+    private val lockscreenToGlanceableHubTransitionViewModel:
+        LockscreenToGlanceableHubTransitionViewModel,
+    private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
+    private val lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
+    private val lockscreenToPrimaryBouncerTransitionViewModel:
+        LockscreenToPrimaryBouncerTransitionViewModel,
+    private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
+    private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+    private val primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
+    private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+    private val primaryBouncerToLockscreenTransitionViewModel:
+        PrimaryBouncerToLockscreenTransitionViewModel,
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val aodBurnInViewModel: AodBurnInViewModel,
     private val aodAlphaViewModel: AodAlphaViewModel,
@@ -110,13 +121,24 @@
                 // The transitions are mutually exclusive, so they are safe to merge to get the last
                 // value emitted by any of them. Do not add flows that cannot make this guarantee.
                 merge(
-                    aodAlphaViewModel.alpha,
-                    lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
-                    glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
-                    lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
-                    primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
-                    alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
-                )
+                        aodAlphaViewModel.alpha,
+                        keyguardInteractor.dismissAlpha.filterNotNull(),
+                        alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                        aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+                        dozingToLockscreenTransitionViewModel.lockscreenAlpha,
+                        glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+                        lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
+                        lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
+                        lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
+                        lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
+                        lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+                        occludedToAodTransitionViewModel.lockscreenAlpha,
+                        occludedToLockscreenTransitionViewModel.lockscreenAlpha,
+                        primaryBouncerToAodTransitionViewModel.lockscreenAlpha,
+                        primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                        primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
+                    )
+                    .onStart { emit(1f) }
             ) { isIdleOnCommunal, alpha ->
                 if (isIdleOnCommunal) {
                     // Keyguard should not show while the communal hub is fully visible. This check
@@ -131,10 +153,13 @@
     }
 
     /** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */
-    val lockscreenStateAlpha: Flow<Float> = aodToLockscreenTransitionViewModel.lockscreenAlpha
+    @Deprecated("only used for legacy status view")
+    fun lockscreenStateAlpha(viewState: ViewStateAccessor): Flow<Float> {
+        return aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState)
+    }
 
     /** For elements that appear and move during the animation -> AOD */
-    val burnInLayerAlpha: Flow<Float> = aodBurnInViewModel.alpha
+    val burnInLayerAlpha: Flow<Float> = aodAlphaViewModel.alpha
 
     fun translationY(params: BurnInParameters): Flow<Float> {
         return aodBurnInViewModel.translationY(params)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
index ce47f3c6..0cfc757 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt
@@ -51,6 +51,8 @@
             onStep = { 1f - it }
         )
 
+    val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         shadeDependentFlows.transitionFlow(
             flowWhenShadeIsNotExpanded =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
index 07c1141..c61b1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.emptyFlow
@@ -47,6 +48,15 @@
     val deviceEntryBackgroundViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(0f)
 
+    /** Lockscreen views alpha */
+    val lockscreenAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            startTime = 233.milliseconds,
+            duration = 250.milliseconds,
+            onStep = { it },
+            onStart = { 0f },
+        )
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
             ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
index 5879d18..942903b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt
@@ -51,6 +51,12 @@
     val deviceEntryBackgroundViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(0f)
 
+    val lockscreenAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION,
+            onStep = { it }
+        )
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
             isUdfpsEnrolledAndEnabled ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
index 284a134..34c9ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
@@ -23,6 +24,7 @@
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.emptyFlow
@@ -58,10 +60,13 @@
 
     val shortcutsAlpha: Flow<Float> =
         transitionAnimation.sharedFlow(
-            duration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION,
+            duration = 250.milliseconds,
+            interpolator = EMPHASIZED_ACCELERATE,
             onStep = { it }
         )
 
+    val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(1f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
index 3671dd4..b4cc196 100644
--- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
@@ -39,7 +39,10 @@
     /**
      * Returns {@link UserHandle} as returned statically by {@link Process#myUserHandle()}.
      *
-     * Please strongly consider using {@link com.android.systemui.settings.UserTracker} instead.
+     * This should not be used to get the "current" user. This information only applies to the
+     * current process, not the current state of SystemUI. Please use
+     * {@link com.android.systemui.settings.UserTracker} if you want to learn about the currently
+     * active user in SystemUI.
      */
     public UserHandle myUserHandle() {
         return Process.myUserHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2968490..fe45df8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -71,7 +71,6 @@
 import android.util.Log;
 import android.util.MathUtils;
 import android.view.HapticFeedbackConstants;
-import android.view.InputDevice;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -1158,9 +1157,9 @@
         // Occluded->Lockscreen
         collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
                 mOccludedToLockscreenTransition, mMainDispatcher);
-        collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
-                setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
         if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+                    setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
             collectFlow(mView,
                     mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(),
                     setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1169,9 +1168,11 @@
         // Lockscreen->Dreaming
         collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
                 mLockscreenToDreamingTransition, mMainDispatcher);
-        collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
-                setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
-                mMainDispatcher);
+        if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
+                    setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+                    mMainDispatcher);
+        }
         collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
                 mLockscreenToDreamingTransitionTranslationY),
                 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1179,8 +1180,10 @@
         // Gone->Dreaming
         collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
                 mGoneToDreamingTransition, mMainDispatcher);
-        collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
-                setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+        if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
+                    setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+        }
         collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY(
                 mGoneToDreamingTransitionTranslationY),
                 setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1188,16 +1191,18 @@
         // Lockscreen->Occluded
         collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
                 mLockscreenToOccludedTransition, mMainDispatcher);
-        collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
-                setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
         if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
+                    setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
             collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
                     setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
         }
 
         // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
-        collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
-                setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+        if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
+                    setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+        }
     }
 
     @VisibleForTesting
@@ -2734,6 +2739,9 @@
     }
 
     private void updateKeyguardBottomAreaAlpha() {
+        if (KeyguardShadeMigrationNssl.isEnabled()) {
+            return;
+        }
         if (mIsOcclusionTransitionRunning) {
             return;
         }
@@ -5057,19 +5065,6 @@
                 return false;
             }
 
-            final boolean isTrackpadTwoOrThreeFingerSwipe = isTrackpadScroll(
-                    mTrackpadGestureFeaturesEnabled, event) || isTrackpadThreeFingerSwipe(
-                    mTrackpadGestureFeaturesEnabled, event);
-
-            // On expanding, single mouse click expands the panel instead of dragging.
-            if (isFullyCollapsed() && (event.isFromSource(InputDevice.SOURCE_MOUSE)
-                    && !isTrackpadTwoOrThreeFingerSwipe)) {
-                if (event.getAction() == MotionEvent.ACTION_UP) {
-                    expand(true /* animate */);
-                }
-                return true;
-            }
-
             /*
              * We capture touch events here and update the expand height here in case according to
              * the users fingers. This also handles multi-touch.
@@ -5090,6 +5085,10 @@
                 mIgnoreXTouchSlop = true;
             }
 
+            final boolean isTrackpadTwoOrThreeFingerSwipe = isTrackpadScroll(
+                    mTrackpadGestureFeaturesEnabled, event) || isTrackpadThreeFingerSwipe(
+                    mTrackpadGestureFeaturesEnabled, event);
+
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     if (QuickStepContract.ALLOW_BACK_GESTURE_IN_SHADE && mAnimateBack) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index ff00cb3..476b054 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -25,31 +25,37 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.Edge
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
-import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
 import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
-import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
@@ -85,67 +91,32 @@
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val shadeInteractor: ShadeInteractor,
     communalInteractor: CommunalInteractor,
+    private val alternateBouncerToGoneTransitionViewModel:
+        AlternateBouncerToGoneTransitionViewModel,
+    private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+    private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
+    private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
+    private val glanceableHubToLockscreenTransitionViewModel:
+        GlanceableHubToLockscreenTransitionViewModel,
+    private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+    private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
+    private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
+    private val lockscreenToGlanceableHubTransitionViewModel:
+        LockscreenToGlanceableHubTransitionViewModel,
+    private val lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
+    private val lockscreenToPrimaryBouncerTransitionViewModel:
+        LockscreenToPrimaryBouncerTransitionViewModel,
+    private val lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
+    private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
     private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
-    lockscreenToGoneTransitionViewModel: LockscreenToGoneTransitionViewModel,
-    alternateBouncerToGoneTransitionViewModel: AlternateBouncerToGoneTransitionViewModel,
-    primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
-    lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
-    dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
-    lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
-    glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
-    lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
+    private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
+    private val primaryBouncerToLockscreenTransitionViewModel:
+        PrimaryBouncerToLockscreenTransitionViewModel,
     private val aodBurnInViewModel: AodBurnInViewModel,
 ) {
     private val statesForConstrainedNotifications: Set<KeyguardState> =
         setOf(AOD, LOCKSCREEN, DOZING, ALTERNATE_BOUNCER, PRIMARY_BOUNCER)
 
-    private val edgeToAlphaViewModel =
-        mapOf<Edge?, (ViewStateAccessor) -> Flow<Float>>(
-            Edge(from = LOCKSCREEN, to = DREAMING) to
-                { _: ViewStateAccessor ->
-                    lockscreenToDreamingTransitionViewModel.lockscreenAlpha
-                },
-            Edge(from = LOCKSCREEN, to = GONE) to
-                { viewState: ViewStateAccessor ->
-                    lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState)
-                },
-            Edge(from = ALTERNATE_BOUNCER, to = GONE) to
-                { _: ViewStateAccessor ->
-                    alternateBouncerToGoneTransitionViewModel.lockscreenAlpha
-                },
-            Edge(from = PRIMARY_BOUNCER, to = GONE) to
-                { _: ViewStateAccessor ->
-                    primaryBouncerToGoneTransitionViewModel.lockscreenAlpha
-                },
-            Edge(from = DREAMING, to = LOCKSCREEN) to
-                { _: ViewStateAccessor ->
-                    dreamingToLockscreenTransitionViewModel.lockscreenAlpha
-                },
-            Edge(from = LOCKSCREEN, to = OCCLUDED) to
-                { _: ViewStateAccessor ->
-                    lockscreenToOccludedTransitionViewModel.lockscreenAlpha
-                },
-            Edge(from = OCCLUDED, to = LOCKSCREEN) to
-                { _: ViewStateAccessor ->
-                    occludedToLockscreenTransitionViewModel.lockscreenAlpha
-                },
-        )
-
-    private val lockscreenTransitionInProgress: Flow<Edge?> =
-        keyguardTransitionInteractor.transitions
-            .map { step ->
-                if (
-                    (step.transitionState == STARTED || step.transitionState == RUNNING) &&
-                        (step.from == LOCKSCREEN || step.to == LOCKSCREEN)
-                ) {
-                    Edge(step.from, step.to)
-                } else {
-                    null
-                }
-            }
-            .distinctUntilChanged()
-            .onStart { emit(null) }
-
     private val lockscreenToGlanceableHubRunning =
         keyguardTransitionInteractor
             .transition(LOCKSCREEN, GLANCEABLE_HUB)
@@ -300,54 +271,79 @@
     private val alphaForShadeAndQsExpansion: Flow<Float> =
         interactor.configurationBasedDimensions
             .flatMapLatest { configurationBasedDimensions ->
-                combine(
+                combineTransform(
                     shadeInteractor.shadeExpansion,
                     shadeInteractor.qsExpansion,
                 ) { shadeExpansion, qsExpansion ->
                     if (shadeExpansion > 0f || qsExpansion > 0f) {
                         if (configurationBasedDimensions.useSplitShade) {
-                            1f
+                            emit(1f)
                         } else {
                             // Fade as QS shade expands
-                            1f - qsExpansion
+                            emit(1f - qsExpansion)
                         }
-                    } else {
-                        // Not visible unless the shade/qs is visible
-                        0f
                     }
                 }
             }
-            .distinctUntilChanged()
+            .onStart { emit(0f) }
+
+    private val alphaWhenGoneAndShadeState: Flow<Float> =
+        combineTransform(
+            keyguardTransitionInteractor.transitions
+                .map { step -> step.to == GONE && step.transitionState == FINISHED }
+                .distinctUntilChanged(),
+            keyguardInteractor.statusBarState,
+        ) { isGoneTransitionFinished, statusBarState ->
+            if (isGoneTransitionFinished && statusBarState == SHADE) {
+                emit(1f)
+            }
+        }
 
     fun expansionAlpha(viewState: ViewStateAccessor): Flow<Float> {
-        // Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
-        // such as when the shade resets. This can happen while the transition to/from LOCKSCREEN
-        // is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
-        // those transitions are in progress. Without this, the alpha value will produce a visible
-        // flicker.
-        return lockscreenTransitionInProgress
-            .flatMapLatest { edge ->
-                edgeToAlphaViewModel.getOrDefault(
-                    edge,
-                    { _: ViewStateAccessor ->
-                        isOnLockscreenWithoutShade.flatMapLatest { isOnLockscreenWithoutShade ->
-                            combineTransform(
-                                keyguardInteractor.keyguardAlpha,
-                                shadeCollpaseFadeIn,
-                                alphaForShadeAndQsExpansion,
-                            ) { alpha, shadeCollpaseFadeIn, alphaForShadeAndQsExpansion ->
-                                if (isOnLockscreenWithoutShade) {
-                                    if (!shadeCollpaseFadeIn) {
-                                        emit(alpha)
-                                    }
-                                } else {
-                                    emit(alphaForShadeAndQsExpansion)
-                                }
-                            }
+        // All transition view models are mututally exclusive, and safe to merge
+        val alphaTransitions =
+            merge(
+                alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+                dozingToLockscreenTransitionViewModel.lockscreenAlpha,
+                dreamingToLockscreenTransitionViewModel.lockscreenAlpha,
+                goneToDreamingTransitionViewModel.lockscreenAlpha,
+                goneToDozingTransitionViewModel.lockscreenAlpha,
+                lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
+                lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
+                lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
+                lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
+                occludedToAodTransitionViewModel.lockscreenAlpha,
+                occludedToLockscreenTransitionViewModel.lockscreenAlpha,
+                primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
+            )
+
+        return merge(
+                alphaTransitions,
+                // Sends a final alpha value of 1f when truly gone, to make sure HUNs appear
+                alphaWhenGoneAndShadeState,
+                // These remaining cases handle alpha changes within an existing state, such as
+                // shade expansion or swipe to dismiss
+                combineTransform(
+                    isOnLockscreenWithoutShade,
+                    shadeCollpaseFadeIn,
+                    alphaForShadeAndQsExpansion,
+                    keyguardInteractor.dismissAlpha,
+                ) {
+                    isOnLockscreenWithoutShade,
+                    shadeCollpaseFadeIn,
+                    alphaForShadeAndQsExpansion,
+                    dismissAlpha ->
+                    if (isOnLockscreenWithoutShade) {
+                        if (!shadeCollpaseFadeIn && dismissAlpha != null) {
+                            emit(dismissAlpha)
                         }
+                    } else {
+                        emit(alphaForShadeAndQsExpansion)
                     }
-                )(viewState)
-            }
+                },
+            )
             .distinctUntilChanged()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index f9702dd..a39bfe0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -81,6 +81,7 @@
         statusContainer.setOnHoverListener(
             statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
         )
+        statusContainer.setOnClickListener { shadeViewController.expand(/* animate= */true) }
 
         progressProvider?.setReadyToHandleTransition(true)
         configurationController.addCallback(configurationListener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
index f3807e4..c381749 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt
@@ -59,6 +59,24 @@
         }
 
     @Test
+    fun lockscreenAlphaStartsFromViewStateAccessorAlpha() =
+        testScope.runTest {
+            val viewState = ViewStateAccessor(alpha = { 0.5f })
+            val alpha by collectLastValue(underTest.lockscreenAlpha(viewState))
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+
+            repository.sendTransitionStep(step(0f))
+            assertThat(alpha).isEqualTo(0.5f)
+
+            repository.sendTransitionStep(step(0.5f))
+            assertThat(alpha).isEqualTo(0.75f)
+
+            repository.sendTransitionStep(step(1f))
+            assertThat(alpha).isEqualTo(1f)
+        }
+
+    @Test
     fun deviceEntryBackgroundView_udfps_alphaFadeIn() =
         testScope.runTest {
             fingerprintPropertyRepository.supportsUdfps()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 17e4e0f..61fee16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -186,6 +186,8 @@
 
         FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository();
         FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                mKosmos.getKeyguardTransitionInteractor();
         KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
                 keyguardRepository,
                 new FakeCommandQueue(),
@@ -194,12 +196,10 @@
                 new FakeKeyguardBouncerRepository(),
                 new ConfigurationInteractor(configurationRepository),
                 shadeRepository,
+                keyguardTransitionInteractor,
                 () -> sceneInteractor);
         CommunalInteractor communalInteractor = mKosmos.getCommunalInteractor();
 
-        KeyguardTransitionInteractor keyguardTransitionInteractor =
-                mKosmos.getKeyguardTransitionInteractor();
-
         mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
         mFromPrimaryBouncerTransitionInteractor =
                 mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 2f765d5..061f88e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -213,6 +213,8 @@
                 mKosmos.getDeviceUnlockedInteractor());
 
         FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                mKosmos.getKeyguardTransitionInteractor();
         KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
                 mKeyguardRepository,
                 new FakeCommandQueue(),
@@ -221,11 +223,9 @@
                 new FakeKeyguardBouncerRepository(),
                 new ConfigurationInteractor(configurationRepository),
                 mShadeRepository,
+                keyguardTransitionInteractor,
                 () -> sceneInteractor);
 
-        KeyguardTransitionInteractor keyguardTransitionInteractor =
-                mKosmos.getKeyguardTransitionInteractor();
-
         mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
         mFromPrimaryBouncerTransitionInteractor =
                 mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index fb105e2..1396a43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -122,6 +122,10 @@
         val shadeRepository = FakeShadeRepository()
         val sceneContainerFlags = FakeSceneContainerFlags()
         val configurationRepository = FakeConfigurationRepository()
+        val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
+        fromLockscreenTransitionInteractor = kosmos.fromLockscreenTransitionInteractor
+        fromPrimaryBouncerTransitionInteractor = kosmos.fromPrimaryBouncerTransitionInteractor
+
         val keyguardInteractor =
             KeyguardInteractor(
                 keyguardRepository,
@@ -131,11 +135,9 @@
                 FakeKeyguardBouncerRepository(),
                 ConfigurationInteractor(configurationRepository),
                 shadeRepository,
+                keyguardTransitionInteractor,
                 { kosmos.sceneInteractor },
             )
-        val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
-        fromLockscreenTransitionInteractor = kosmos.fromLockscreenTransitionInteractor
-        fromPrimaryBouncerTransitionInteractor = kosmos.fromPrimaryBouncerTransitionInteractor
 
         whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
         shadeInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 9055ba4..2da88e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -47,6 +47,8 @@
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.mockLargeScreenHeaderHelper
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.statusbar.policy.splitShadeStateController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
@@ -65,6 +67,7 @@
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
     val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
+    val splitShadeStateController = mock(SplitShadeStateController::class.java)
     lateinit var translationYFlow: MutableStateFlow<Float>
 
     val kosmos =
@@ -77,6 +80,7 @@
 
     init {
         kosmos.aodBurnInViewModel = aodBurnInViewModel
+        kosmos.splitShadeStateController = splitShadeStateController
     }
     val testScope = kosmos.testScope
     val configurationRepository = kosmos.fakeConfigurationRepository
@@ -93,7 +97,7 @@
 
     @Before
     fun setUp() {
-        overrideResource(R.bool.config_use_split_notification_shade, false)
+        whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())).thenReturn(false)
         translationYFlow = MutableStateFlow(0f)
         whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow)
         underTest = kosmos.sharedNotificationContainerViewModel
@@ -102,7 +106,8 @@
     @Test
     fun validateMarginStartInSplitShade() =
         testScope.runTest {
-            overrideResource(R.bool.config_use_split_notification_shade, true)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -115,7 +120,8 @@
     @Test
     fun validateMarginStart() =
         testScope.runTest {
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -130,7 +136,9 @@
         testScope.runTest {
             mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            overrideResource(R.bool.config_use_split_notification_shade, true)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+            overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
@@ -147,12 +155,13 @@
         testScope.runTest {
             mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            overrideResource(R.bool.config_use_split_notification_shade, true)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+            overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
-
             configurationRepository.onAnyConfigurationChange()
 
             // Should directly use the header height (flagged on value)
@@ -162,7 +171,8 @@
     @Test
     fun validatePaddingTop() =
         testScope.runTest {
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
@@ -421,7 +431,8 @@
             val bounds by collectLastValue(underTest.bounds)
 
             // When not in split shade
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             configurationRepository.onAnyConfigurationChange()
             runCurrent()
 
@@ -443,7 +454,9 @@
 
             // When in split shade
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            overrideResource(R.bool.config_use_split_notification_shade, true)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+            overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
@@ -470,7 +483,9 @@
 
             // When in split shade
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            overrideResource(R.bool.config_use_split_notification_shade, true)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+            overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
@@ -528,7 +543,8 @@
 
             showLockscreen()
 
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -551,7 +567,8 @@
 
             showLockscreen()
 
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -587,7 +604,8 @@
             // Show lockscreen with shade expanded
             showLockscreenWithShadeExpanded()
 
-            overrideResource(R.bool.config_use_split_notification_shade, false)
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 76c9740..56fc7b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -60,6 +60,7 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
@@ -162,7 +163,8 @@
         MockitoAnnotations.initMocks(this);
 
         when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
-
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                mKosmos.getKeyguardTransitionInteractor();
         mKeyguardInteractor = new KeyguardInteractor(
                 mKeyguardRepository,
                 mCommandQueue,
@@ -171,6 +173,7 @@
                 new FakeKeyguardBouncerRepository(),
                 new ConfigurationInteractor(new FakeConfigurationRepository()),
                 new FakeShadeRepository(),
+                keyguardTransitionInteractor,
                 () -> mKosmos.getSceneInteractor());
         mViewModel =
                 new KeyguardStatusBarViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index b7560ad..1687ccb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -22,15 +22,16 @@
 import android.app.StatusBarManager.WINDOW_STATUS_BAR
 import android.view.LayoutInflater
 import android.view.MotionEvent
+import android.view.View
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.OnPreDrawListener
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeControllerImpl
@@ -48,8 +49,6 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
-import java.util.Optional
-import javax.inject.Provider
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
@@ -60,6 +59,8 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import java.util.Optional
+import javax.inject.Provider
 
 @SmallTest
 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@@ -98,7 +99,7 @@
             val parent = FrameLayout(mContext) // add parent to keep layout params
             view =
                 LayoutInflater.from(mContext).inflate(R.layout.status_bar, parent, false)
-                    as PhoneStatusBarView
+                        as PhoneStatusBarView
             controller = createAndInitController(view)
         }
     }
@@ -231,6 +232,27 @@
         verify(centralSurfacesImpl).setInteracting(any(), any())
     }
 
+    @Test
+    fun shadeIsExpandedOnStatusIconClick() {
+        val view = createViewMock()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            controller = createAndInitController(view)
+        }
+        val statusContainer = view.requireViewById<View>(R.id.system_icons)
+        statusContainer.performClick()
+        verify(shadeViewController).expand(any())
+    }
+
+    @Test
+    fun shadeIsNotExpandedOnStatusBarGeneralClick() {
+        val view = createViewMock()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            controller = createAndInitController(view)
+        }
+        view.performClick()
+        verify(shadeViewController, never()).expand(any())
+    }
+
     private fun getCommandQueueCallback(): CommandQueue.Callbacks {
         val captor = argumentCaptor<CommandQueue.Callbacks>()
         verify(commandQueue).addCallback(captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index ca0e526..76913e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
@@ -61,6 +62,7 @@
             FakeKeyguardBouncerRepository(),
             ConfigurationInteractor(FakeConfigurationRepository()),
             FakeShadeRepository(),
+            kosmos.keyguardTransitionInteractor,
         ) {
             kosmos.sceneInteractor
         }
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 97bd96d..d87df0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -420,6 +420,8 @@
                 mKosmos.getDeviceUnlockedInteractor());
 
         FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags();
+        KeyguardTransitionInteractor keyguardTransitionInteractor =
+                mKosmos.getKeyguardTransitionInteractor();
         KeyguardInteractor keyguardInteractor = new KeyguardInteractor(
                 keyguardRepository,
                 new FakeCommandQueue(),
@@ -428,11 +430,9 @@
                 new FakeKeyguardBouncerRepository(),
                 new ConfigurationInteractor(configurationRepository),
                 shadeRepository,
+                keyguardTransitionInteractor,
                 () -> sceneInteractor);
 
-        KeyguardTransitionInteractor keyguardTransitionInteractor =
-                mKosmos.getKeyguardTransitionInteractor();
-
         mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor();
         mFromPrimaryBouncerTransitionInteractor =
                 mKosmos.getFromPrimaryBouncerTransitionInteractor();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 0bba36b..3893a9b7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -30,6 +31,8 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.flow.MutableSharedFlow
 
 /**
  * Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
@@ -50,6 +53,11 @@
         sceneInteractor: SceneInteractor = mock(),
         powerInteractor: PowerInteractor = PowerInteractorFactory.create().powerInteractor,
     ): WithDependencies {
+        // Mock this until the class is replaced by kosmos
+        val keyguardTransitionInteractor: KeyguardTransitionInteractor = mock()
+        val currentKeyguardStateFlow = MutableSharedFlow<KeyguardState>()
+        whenever(keyguardTransitionInteractor.currentKeyguardState)
+            .thenReturn(currentKeyguardStateFlow)
         return WithDependencies(
             repository = repository,
             commandQueue = commandQueue,
@@ -67,6 +75,7 @@
                 configurationInteractor = ConfigurationInteractor(configurationRepository),
                 shadeRepository = shadeRepository,
                 sceneInteractorProvider = { sceneInteractor },
+                keyguardTransitionInteractor = keyguardTransitionInteractor,
                 powerInteractor = powerInteractor,
             ),
         )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
index 58d99b5..5140a9f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
@@ -36,6 +36,7 @@
             bouncerRepository = keyguardBouncerRepository,
             configurationInteractor = configurationInteractor,
             shadeRepository = shadeRepository,
+            keyguardTransitionInteractor = keyguardTransitionInteractor,
             sceneInteractorProvider = { sceneInteractor },
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
index 0c38fd9..6df7493 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
@@ -26,7 +26,6 @@
         KeyguardTransitionInteractor(
             scope = applicationCoroutineScope,
             repository = keyguardTransitionRepository,
-            keyguardInteractor = Lazy { keyguardInteractor },
             fromLockscreenTransitionInteractor = Lazy { fromLockscreenTransitionInteractor },
             fromPrimaryBouncerTransitionInteractor =
                 Lazy { fromPrimaryBouncerTransitionInteractor },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
index 6b89e0f..9fb3284 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
@@ -18,7 +18,6 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
@@ -26,8 +25,8 @@
 
 val Kosmos.aodAlphaViewModel by Fixture {
     AodAlphaViewModel(
-        keyguardInteractor = keyguardInteractor,
         keyguardTransitionInteractor = keyguardTransitionInteractor,
-        occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+        goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+        goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
new file mode 100644
index 0000000..4daf460
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+val Kosmos.goneToDozingTransitionViewModel by Fixture {
+    GoneToDozingTransitionViewModel(
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 24bb9c5..4939237b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -37,14 +37,24 @@
         communalInteractor = communalInteractor,
         keyguardTransitionInteractor = keyguardTransitionInteractor,
         notificationsKeyguardInteractor = notificationsKeyguardInteractor,
-        aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
-        lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
         alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
+        aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+        dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
+        glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+        lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
+        lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
+        lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
+        lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+        lockscreenToPrimaryBouncerTransitionViewModel =
+            lockscreenToPrimaryBouncerTransitionViewModel,
+        occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+        occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+        primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel,
         primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
+        primaryBouncerToLockscreenTransitionViewModel =
+            primaryBouncerToLockscreenTransitionViewModel,
         screenOffAnimationController = screenOffAnimationController,
         aodBurnInViewModel = aodBurnInViewModel,
         aodAlphaViewModel = aodAlphaViewModel,
-        lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
-        glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 30d4105..8882de0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -21,14 +21,21 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.dreamingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.goneToDozingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.goneToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.lockscreenToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.occludedToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.occludedToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToGoneTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToLockscreenTransitionViewModel
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.applicationCoroutineScope
@@ -43,15 +50,24 @@
         keyguardTransitionInteractor = keyguardTransitionInteractor,
         shadeInteractor = shadeInteractor,
         communalInteractor = communalInteractor,
-        occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
-        lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
         alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
-        primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
-        lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+        aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+        dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
         dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel,
-        lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
+        goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
+        goneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel,
         glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+        lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
         lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
+        lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
+        lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+        lockscreenToPrimaryBouncerTransitionViewModel =
+            lockscreenToPrimaryBouncerTransitionViewModel,
+        occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+        occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+        primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
+        primaryBouncerToLockscreenTransitionViewModel =
+            primaryBouncerToLockscreenTransitionViewModel,
         aodBurnInViewModel = aodBurnInViewModel,
     )
 }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 35ce481..132804f 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -24,6 +24,46 @@
     visibility: ["//visibility:public"],
 }
 
+java_library_host {
+    name: "ravenwood-helper-libcore-runtime.host",
+    srcs: [
+        "runtime-helper-src/libcore-fake/**/*.java",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_host_for_device {
+    name: "ravenwood-helper-libcore-runtime",
+    libs: [
+        "ravenwood-helper-libcore-runtime.host",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_library {
+    name: "ravenwood-helper-framework-runtime",
+    srcs: [
+        "runtime-helper-src/framework/**/*.java",
+    ],
+    libs: [
+        "framework-minus-apex.ravenwood",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Combine ravenwood-helper-*-runtime and create a single library, which we include
+// in the ravenwood runtime.
+// We do it this way rather than including the individual jars in the runtime, because
+// for some reason we couldn't include a java_host_for_device module in the ravenwood runtime.
+java_library {
+    name: "ravenwood-helper-runtime",
+    defaults: ["ravenwood-internal-only-visibility-java"],
+    static_libs: [
+        "ravenwood-helper-framework-runtime",
+        "ravenwood-helper-libcore-runtime",
+    ],
+}
+
 java_library {
     name: "ravenwood-junit-impl",
     srcs: [
@@ -58,16 +98,6 @@
     visibility: ["//visibility:public"],
 }
 
-java_library {
-    // Prefixed with "200" to ensure it's sorted early in Tradefed classpath
-    // so that we provide a concrete implementation before Mainline stubs
-    name: "200-kxml2-android",
-    static_libs: [
-        "kxml2-android",
-    ],
-    visibility: ["//frameworks/base"],
-}
-
 java_host_for_device {
     name: "androidx.test.monitor-for-device",
     libs: [
diff --git a/ravenwood/api-maintainers.md b/ravenwood/api-maintainers.md
index d84cb67..4b2f968 100644
--- a/ravenwood/api-maintainers.md
+++ b/ravenwood/api-maintainers.md
@@ -82,7 +82,7 @@
 
 ```
 @RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.MyComplexClass_host")
+@RavenwoodNativeSubstitutionClass("com.android.platform.test.ravenwood.nativesubstitution.MyComplexClass_host")
 public class MyComplexClass {
     private static native void nativeDoThing(long nativePtr);
 ...
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
index eba9910..f38d565 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/CursorWindow_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
index 6480cfc..55d4ffb 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import com.android.internal.os.RuntimeInit;
 
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
index cdfa302..5930a14 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import android.util.Log;
 import android.util.Log.Level;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
similarity index 99%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
index 4d39d88..7414110 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import android.os.BadParcelableException;
 import android.os.Parcel;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
index a5d0fc6..9486651 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import android.os.BadParcelableException;
 import android.os.Parcel;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
similarity index 97%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
index 65da4a1..5e81124 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
index 0ebaac60..2d79914 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import static android.os.ParcelFileDescriptor.MODE_APPEND;
 import static android.os.ParcelFileDescriptor.MODE_CREATE;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
similarity index 99%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
index d63bff6..81ad31e 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
similarity index 98%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
index 2f6a361..eba6c8b 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.nativesubstitution;
+package com.android.platform.test.ravenwood.nativesubstitution;
 
 import android.util.SparseArray;
 
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
similarity index 96%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
rename to ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index fbcc648..1e12030 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -13,9 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.hoststubgen.runtimehelper;
-
-import com.android.hoststubgen.hosthelper.HostTestException;
+package com.android.platform.test.ravenwood.runtimehelper;
 
 import java.io.File;
 import java.io.PrintStream;
@@ -79,7 +77,7 @@
 
     private static void ensurePropertyNotSet(String key) {
         if (System.getProperty(key) != null) {
-            throw new HostTestException("System property \"" + key + "\" is set unexpectedly");
+            throw new RuntimeException("System property \"" + key + "\" is set unexpectedly");
         }
     }
 
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/android/system/ErrnoException.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/android/system/ErrnoException.java
rename to ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
rename to ravenwood/runtime-helper-src/libcore-fake/com/android/okhttp/internalandroidapi/Dns.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
rename to ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/io/IoUtils.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/io/IoUtils.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/EmptyArray.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/EmptyArray.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/HexEncoding.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/HexEncoding.java
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/SneakyThrow.java
similarity index 100%
rename from tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
rename to ravenwood/runtime-helper-src/libcore-fake/libcore/util/SneakyThrow.java
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index e349fa3..babb6c2 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -22,6 +22,8 @@
 import static android.app.Notification.FLAG_LOCAL_ONLY;
 import static android.app.Notification.FLAG_NO_CLEAR;
 import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_PUBLIC;
 
 import android.annotation.NonNull;
 import android.app.Notification;
@@ -145,7 +147,8 @@
                     mUngroupedNotifications.getOrDefault(key, new ArrayMap<>());
 
             NotificationAttributes attr = new NotificationAttributes(sbn.getNotification().flags,
-                    sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+                    sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+                    sbn.getNotification().visibility);
             children.put(sbn.getKey(), attr);
             mUngroupedNotifications.put(key, children);
 
@@ -158,25 +161,29 @@
         if (notificationsToGroup.size() > 0) {
             if (autogroupSummaryExists) {
                 NotificationAttributes attr = new NotificationAttributes(flags,
-                        sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+                        sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+                        VISIBILITY_PRIVATE);
                 if (Flags.autogroupSummaryIconUpdate()) {
-                    attr = updateAutobundledSummaryIcon(sbn.getPackageName(), childrenAttr, attr);
+                    attr = updateAutobundledSummaryAttributes(sbn.getPackageName(), childrenAttr,
+                            attr);
                 }
 
                 mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), attr);
             } else {
                 Icon summaryIcon = sbn.getNotification().getSmallIcon();
                 int summaryIconColor = sbn.getNotification().color;
+                int summaryVisibility = VISIBILITY_PRIVATE;
                 if (Flags.autogroupSummaryIconUpdate()) {
-                    // Calculate the initial summary icon and icon color
-                    NotificationAttributes iconAttr = getAutobundledSummaryIconAndColor(
+                    // Calculate the initial summary icon, icon color and visibility
+                    NotificationAttributes iconAttr = getAutobundledSummaryAttributes(
                             sbn.getPackageName(), childrenAttr);
                     summaryIcon = iconAttr.icon;
                     summaryIconColor = iconAttr.iconColor;
+                    summaryVisibility = iconAttr.visibility;
                 }
 
                 NotificationAttributes attr = new NotificationAttributes(flags, summaryIcon,
-                        summaryIconColor);
+                        summaryIconColor, summaryVisibility);
                 mCallback.addAutoGroupSummary(sbn.getUserId(), sbn.getPackageName(), sbn.getKey(),
                         attr);
             }
@@ -238,18 +245,19 @@
             mCallback.removeAutoGroupSummary(userId, sbn.getPackageName());
         } else {
             NotificationAttributes attr = new NotificationAttributes(summaryFlags,
-                    sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
-            boolean iconUpdated = false;
+                    sbn.getNotification().getSmallIcon(), sbn.getNotification().color,
+                    VISIBILITY_PRIVATE);
+            boolean attributesUpdated = false;
             if (Flags.autogroupSummaryIconUpdate()) {
-                NotificationAttributes newAttr = updateAutobundledSummaryIcon(sbn.getPackageName(),
-                        childrenAttrs, attr);
+                NotificationAttributes newAttr = updateAutobundledSummaryAttributes(
+                        sbn.getPackageName(), childrenAttrs, attr);
                 if (!newAttr.equals(attr)) {
-                    iconUpdated = true;
+                    attributesUpdated = true;
                     attr = newAttr;
                 }
             }
 
-            if (updateSummaryFlags || iconUpdated) {
+            if (updateSummaryFlags || attributesUpdated) {
                 mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), attr);
             }
         }
@@ -268,12 +276,13 @@
         }
     }
 
-    NotificationAttributes getAutobundledSummaryIconAndColor(@NonNull String packageName,
+    NotificationAttributes getAutobundledSummaryAttributes(@NonNull String packageName,
             @NonNull List<NotificationAttributes> childrenAttr) {
         Icon newIcon = null;
         boolean childrenHaveSameIcon = true;
         int newColor = Notification.COLOR_INVALID;
         boolean childrenHaveSameColor = true;
+        int newVisibility = VISIBILITY_PRIVATE;
 
         // Both the icon drawable and the icon background color are updated according to this rule:
         // - if all child icons are identical => use the common icon
@@ -296,6 +305,10 @@
                     childrenHaveSameColor = false;
                 }
             }
+            // Check for visibility. If at least one child is public, then set to public
+            if (state.visibility == VISIBILITY_PUBLIC) {
+                newVisibility = VISIBILITY_PUBLIC;
+            }
         }
         if (!childrenHaveSameIcon) {
             newIcon = getMonochromeAppIcon(packageName);
@@ -304,13 +317,13 @@
             newColor = COLOR_DEFAULT;
         }
 
-        return new NotificationAttributes(0, newIcon, newColor);
+        return new NotificationAttributes(0, newIcon, newColor, newVisibility);
     }
 
-    NotificationAttributes updateAutobundledSummaryIcon(@NonNull String packageName,
+    NotificationAttributes updateAutobundledSummaryAttributes(@NonNull String packageName,
             @NonNull List<NotificationAttributes> childrenAttr,
             @NonNull NotificationAttributes oldAttr) {
-        NotificationAttributes newAttr = getAutobundledSummaryIconAndColor(packageName,
+        NotificationAttributes newAttr = getAutobundledSummaryAttributes(packageName,
                 childrenAttr);
         Icon newIcon = newAttr.icon;
         int newColor = newAttr.iconColor;
@@ -321,7 +334,7 @@
             newColor = oldAttr.iconColor;
         }
 
-        return new NotificationAttributes(oldAttr.flags, newIcon, newColor);
+        return new NotificationAttributes(oldAttr.flags, newIcon, newColor, newAttr.visibility);
     }
 
     /**
@@ -358,17 +371,20 @@
         public final int flags;
         public final int iconColor;
         public final Icon icon;
+        public final int visibility;
 
-        public NotificationAttributes(int flags, Icon icon, int iconColor) {
+        public NotificationAttributes(int flags, Icon icon, int iconColor, int visibility) {
             this.flags = flags;
             this.icon = icon;
             this.iconColor = iconColor;
+            this.visibility = visibility;
         }
 
         public NotificationAttributes(@NonNull NotificationAttributes attr) {
             this.flags = attr.flags;
             this.icon = attr.icon;
             this.iconColor = attr.iconColor;
+            this.visibility = attr.visibility;
         }
 
         @Override
@@ -379,12 +395,13 @@
             if (!(o instanceof NotificationAttributes that)) {
                 return false;
             }
-            return flags == that.flags && iconColor == that.iconColor && icon.sameAs(that.icon);
+            return flags == that.flags && iconColor == that.iconColor && icon.sameAs(that.icon)
+                    && visibility == that.visibility;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(flags, iconColor, icon);
+            return Objects.hash(flags, iconColor, icon, visibility);
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ea4e67a..d751186 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1038,15 +1038,17 @@
         }
         int oldFlags = summary.getSbn().getNotification().flags;
 
-        boolean iconUpdated =
+        boolean attributesUpdated =
                 !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon())
-                || summaryAttr.iconColor != summary.getSbn().getNotification().color;
+                || summaryAttr.iconColor != summary.getSbn().getNotification().color
+                || summaryAttr.visibility != summary.getSbn().getNotification().visibility;
 
-        if (oldFlags != summaryAttr.flags || iconUpdated) {
+        if (oldFlags != summaryAttr.flags || attributesUpdated) {
             summary.getSbn().getNotification().flags =
                     summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags;
             summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon);
             summary.getSbn().getNotification().color = summaryAttr.iconColor;
+            summary.getSbn().getNotification().visibility = summaryAttr.visibility;
             mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
                     mPostNotificationTrackerFactory.newTracker(null)));
         }
@@ -2939,7 +2941,8 @@
             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
                     NotificationAttributes summaryAttr) {
                 NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey,
-                        summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor);
+                        summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor,
+                        summaryAttr.visibility);
                 if (r != null) {
                     final boolean isAppForeground =
                             mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
@@ -6725,7 +6728,7 @@
 
     // Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
     NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
-            int flagsToSet, Icon summaryIcon, int summaryIconColor) {
+            int flagsToSet, Icon summaryIcon, int summaryIconColor, int summaryVisibilty) {
         NotificationRecord summaryRecord = null;
         boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
         synchronized (mNotificationLock) {
@@ -6760,6 +6763,7 @@
                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
                                 .setFlag(flagsToSet, true)
                                 .setColor(summaryIconColor)
+                                .setVisibility(summaryVisibilty)
                                 .build();
                 summaryNotification.extras.putAll(extras);
                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index d644235..449e9ab 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -240,7 +240,7 @@
 
     @Override
     protected boolean canRestoreAnyVersion() {
-        return false;
+        return true;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java b/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
index 62a637e..3077fb8 100644
--- a/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
+++ b/services/core/java/com/android/server/wearable/RemoteWearableSensingService.java
@@ -257,6 +257,55 @@
                                         statusCallback));
     }
 
+    /**
+     * Request the wearable to start hotword recognition.
+     *
+     * @param wearableHotwordCallback The callback to send hotword audio data and format to.
+     * @param statusCallback The callback for service status.
+     */
+    public void startHotwordRecognition(
+            RemoteCallback wearableHotwordCallback, RemoteCallback statusCallback) {
+        if (DEBUG) {
+            Slog.i(TAG, "Starting to listen for hotword.");
+        }
+        var unused =
+                post(
+                        service ->
+                                service.startHotwordRecognition(
+                                        wearableHotwordCallback, statusCallback));
+    }
+
+    /**
+     * Request the wearable to stop hotword recognition.
+     *
+     * @param statusCallback The callback for service status.
+     */
+    public void stopHotwordRecognition(RemoteCallback statusCallback) {
+        if (DEBUG) {
+            Slog.i(TAG, "Stopping hotword recognition.");
+        }
+        var unused = post(service -> service.stopHotwordRecognition(statusCallback));
+    }
+
+    /**
+     * Signals to the {@link WearableSensingService} that hotword audio data is accepted by the
+     * {@link android.service.voice.HotwordDetectionService} as valid hotword.
+     */
+    public void onValidatedByHotwordDetectionService() {
+        if (DEBUG) {
+            Slog.i(TAG, "Requesting hotword audio data egress.");
+        }
+        var unused = post(service -> service.onValidatedByHotwordDetectionService());
+    }
+
+    /** Stops the active hotword audio stream from the wearable. */
+    public void stopActiveHotwordAudio() {
+        if (DEBUG) {
+            Slog.i(TAG, "Stopping hotword audio.");
+        }
+        var unused = post(service -> service.stopActiveHotwordAudio());
+    }
+
     private static class SecureWearableConnectionContext {
         final ParcelFileDescriptor mSecureWearableConnection;
         final RemoteCallback mStatusCallback;
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
index 9ba4433..2b43203 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wearable;
 
+import static android.service.wearable.WearableSensingService.HOTWORD_AUDIO_STREAM_BUNDLE_KEY;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,18 +30,23 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SharedMemory;
+import android.service.voice.HotwordAudioStream;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
 import android.system.OsConstants;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 import com.android.server.infra.AbstractPerUserSystemService;
 
 import java.io.IOException;
@@ -58,6 +65,7 @@
     @VisibleForTesting
     RemoteWearableSensingService mRemoteService;
 
+    @Nullable private VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
     private ComponentName mComponentName;
     private final Object mSecureChannelLock = new Object();
 
@@ -99,6 +107,15 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private boolean ensureVoiceInteractionManagerInternalInitiated() {
+        if (mVoiceInteractionManagerInternal == null) {
+            mVoiceInteractionManagerInternal =
+                    LocalServices.getService(VoiceInteractionManagerInternal.class);
+        }
+        return mVoiceInteractionManagerInternal != null;
+    }
+
     /**
      * get the currently bound component name.
      */
@@ -334,4 +351,109 @@
                     dataType, dataRequestObserverId, packageName, statusCallback);
         }
     }
+
+    /** Handles starting hotword listening. */
+    public void onStartHotwordRecognition(
+            ComponentName targetVisComponentName, RemoteCallback statusCallback) {
+        synchronized (mLock) {
+            if (!setUpServiceIfNeeded()) {
+                Slog.w(TAG, "Detection service is not available at this moment.");
+                notifyStatusCallback(
+                        statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            if (!ensureVoiceInteractionManagerInternalInitiated()) {
+                Slog.w(TAG, "Voice interaction manager is not available at this moment.");
+                notifyStatusCallback(
+                        statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            ensureRemoteServiceInitiated();
+            mRemoteService.startHotwordRecognition(
+                    createWearableHotwordCallback(targetVisComponentName), statusCallback);
+        }
+    }
+
+    /** Handles stopping hotword listening. */
+    public void onStopHotwordRecognition(RemoteCallback statusCallback) {
+        synchronized (mLock) {
+            if (!setUpServiceIfNeeded()) {
+                Slog.w(TAG, "Detection service is not available at this moment.");
+                notifyStatusCallback(
+                        statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            ensureRemoteServiceInitiated();
+            mRemoteService.stopHotwordRecognition(statusCallback);
+        }
+    }
+
+    private void onValidatedByHotwordDetectionService() {
+        synchronized (mLock) {
+            if (!setUpServiceIfNeeded()) {
+                Slog.w(TAG, "Wearable sensing service is not available at this moment.");
+                return;
+            }
+            ensureRemoteServiceInitiated();
+            mRemoteService.onValidatedByHotwordDetectionService();
+        }
+    }
+
+    private void stopActiveHotwordAudio() {
+        synchronized (mLock) {
+            if (!setUpServiceIfNeeded()) {
+                Slog.w(TAG, "Wearable sensing service is not available at this moment.");
+                return;
+            }
+            ensureRemoteServiceInitiated();
+            mRemoteService.stopActiveHotwordAudio();
+        }
+    }
+
+    private RemoteCallback createWearableHotwordCallback(ComponentName targetVisComponentName) {
+        return new RemoteCallback(
+                result -> {
+                    HotwordAudioStream hotwordAudioStream =
+                            result.getParcelable(
+                                    HOTWORD_AUDIO_STREAM_BUNDLE_KEY, HotwordAudioStream.class);
+                    if (hotwordAudioStream == null) {
+                        Slog.w(TAG, "No hotword audio stream received, unable to process hotword.");
+                        return;
+                    }
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        mVoiceInteractionManagerInternal.startListeningFromWearable(
+                                hotwordAudioStream.getAudioStreamParcelFileDescriptor(),
+                                hotwordAudioStream.getAudioFormat(),
+                                hotwordAudioStream.getMetadata(),
+                                targetVisComponentName,
+                                getUserId(),
+                                createHotwordDetectionCallback());
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                });
+    }
+
+    private WearableHotwordDetectionCallback createHotwordDetectionCallback() {
+        return new WearableHotwordDetectionCallback() {
+            @Override
+            public void onDetected() {
+                Slog.i(TAG, "hotwordDetectionCallback onDetected.");
+                onValidatedByHotwordDetectionService();
+            }
+
+            @Override
+            public void onRejected() {
+                Slog.i(TAG, "hotwordDetectionCallback onRejected.");
+                stopActiveHotwordAudio();
+            }
+
+            @Override
+            public void onError(String errorMessage) {
+                Slog.i(TAG, "hotwordDetectionCallback onError. ErrorMessage: " + errorMessage);
+                stopActiveHotwordAudio();
+            }
+        };
+    }
 }
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
index 78952fa..00c3026 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
@@ -496,6 +496,42 @@
         }
 
         @Override
+        public void startHotwordRecognition(
+                ComponentName targetVisComponentName, RemoteCallback statusCallback) {
+            Slog.i(TAG, "WearableSensingManagerInternal startHotwordRecognition.");
+            Objects.requireNonNull(statusCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available.");
+                WearableSensingManagerPerUserService.notifyStatusCallback(
+                        statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            callPerUserServiceIfExist(
+                    service ->
+                            service.onStartHotwordRecognition(
+                                    targetVisComponentName, statusCallback),
+                    statusCallback);
+        }
+
+        @Override
+        public void stopHotwordRecognition(RemoteCallback statusCallback) {
+            Slog.i(TAG, "WearableSensingManagerInternal stopHotwordRecognition.");
+            Objects.requireNonNull(statusCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available.");
+                WearableSensingManagerPerUserService.notifyStatusCallback(
+                        statusCallback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            callPerUserServiceIfExist(
+                    service -> service.onStopHotwordRecognition(statusCallback), statusCallback);
+        }
+
+        @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
                 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
             new WearableSensingShellCommand(WearableSensingManagerService.this).exec(
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
index 817901f..fa2d9bf 100644
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
@@ -322,15 +322,17 @@
             var listener = trustedPresentationInfo.mListener;
             boolean lastState = trustedPresentationInfo.mLastComputedTrustedPresentationState;
             boolean newState =
-                    (alpha >= trustedPresentationInfo.mThresholds.minAlpha) && (fractionRendered
-                            >= trustedPresentationInfo.mThresholds.minFractionRendered);
+                    (alpha >= trustedPresentationInfo.mThresholds.getMinAlpha())
+                            && (fractionRendered >= trustedPresentationInfo.mThresholds
+                                    .getMinFractionRendered());
             trustedPresentationInfo.mLastComputedTrustedPresentationState = newState;
 
             ProtoLog.v(WM_DEBUG_TPL,
                     "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f "
                             + "minFractionRendered=%f",
-                    lastState, newState, alpha, trustedPresentationInfo.mThresholds.minAlpha,
-                    fractionRendered, trustedPresentationInfo.mThresholds.minFractionRendered);
+                    lastState, newState, alpha, trustedPresentationInfo.mThresholds.getMinAlpha(),
+                    fractionRendered, trustedPresentationInfo.mThresholds
+                            .getMinFractionRendered());
 
             if (lastState && !newState) {
                 // We were in the trusted presentation state, but now we left it,
@@ -350,13 +352,15 @@
                 trustedPresentationInfo.mEnteredTrustedPresentationStateTime = currTimeMs;
                 mHandler.postDelayed(() -> {
                     computeTpl(mLastWindowHandles);
-                }, (long) (trustedPresentationInfo.mThresholds.stabilityRequirementMs * 1.5));
+                }, (long) (trustedPresentationInfo.mThresholds
+                            .getStabilityRequirementMillis() * 1.5));
             }
 
             // Has the timer elapsed, but we are still in the state? Emit a callback if needed
             if (!trustedPresentationInfo.mLastReportedTrustedPresentationState && newState && (
                     currTimeMs - trustedPresentationInfo.mEnteredTrustedPresentationStateTime
-                            > trustedPresentationInfo.mThresholds.stabilityRequirementMs)) {
+                            > trustedPresentationInfo.mThresholds
+                                        .getStabilityRequirementMillis())) {
                 trustedPresentationInfo.mLastReportedTrustedPresentationState = true;
                 addListenerUpdate(listenerUpdates, listener,
                         trustedPresentationInfo.mId, /*presentationState*/ true);
@@ -413,15 +417,6 @@
             mThresholds = thresholds;
             mId = id;
             mListener = listener;
-            checkValid(thresholds);
-        }
-
-        private void checkValid(TrustedPresentationThresholds thresholds) {
-            if (thresholds.minAlpha <= 0 || thresholds.minFractionRendered <= 0
-                    || thresholds.stabilityRequirementMs < 1) {
-                throw new IllegalArgumentException(
-                        "TrustedPresentationThresholds values are invalid");
-            }
         }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 105dc88..0ccf810c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -102,6 +102,9 @@
             DevicePolicyIdentifiers.getIdentifierForUserRestriction(
                     UserManager.DISALLOW_CELLULAR_2G);
 
+    //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit
+    private static final int DEFAULT_POLICY_SIZE_LIMIT = -1;
+
     private final Context mContext;
     private final UserManager mUserManager;
 
@@ -122,10 +125,11 @@
      * Map containing the current set of admins in each user with active policies.
      */
     private final SparseArray<Set<EnforcingAdmin>> mEnforcingAdmins;
+
     private final SparseArray<HashMap<EnforcingAdmin, Integer>> mAdminPolicySize;
 
-    //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit
-    private static final int POLICY_SIZE_LIMIT = 99999;
+    private int mPolicySizeLimit = DEFAULT_POLICY_SIZE_LIMIT;
+
     private final DeviceAdminServiceController mDeviceAdminServiceController;
 
     DevicePolicyEngine(
@@ -1594,7 +1598,9 @@
             existingPolicySize = sizeOf(policyState.getPoliciesSetByAdmins().get(admin));
         }
         int policySize = sizeOf(value);
-        if (currentAdminPoliciesSize + policySize - existingPolicySize < POLICY_SIZE_LIMIT) {
+        // Policy size limit is disabled if mPolicySizeLimit is -1.
+        if (mPolicySizeLimit == -1
+                || currentAdminPoliciesSize + policySize - existingPolicySize < mPolicySizeLimit) {
             increasePolicySizeForAdmin(
                     admin, /* policySizeDiff = */ policySize - existingPolicySize);
             return true;
@@ -1642,6 +1648,26 @@
         }
     }
 
+    /**
+     * Updates the max allowed size limit for policies per admin. Setting it to -1, disables
+     * the limitation.
+     */
+    void setMaxPolicyStorageLimit(int storageLimit) {
+        if (storageLimit < DEFAULT_POLICY_SIZE_LIMIT && storageLimit != -1) {
+            throw new IllegalArgumentException("Can't set a size limit less than the minimum "
+                    + "allowed size.");
+        }
+        mPolicySizeLimit = storageLimit;
+    }
+
+    /**
+     * Returns the max allowed size limit for policies per admin. -1 means the limitation is
+     * disabled.
+     */
+    int getMaxPolicyStorageLimit() {
+        return mPolicySizeLimit;
+    }
+
     public void dump(IndentingPrintWriter pw) {
         synchronized (mLock) {
             pw.println("Local Policies: ");
@@ -1761,6 +1787,7 @@
         private static final String TAG_ENFORCING_ADMIN_AND_SIZE = "enforcing-admin-and-size";
         private static final String TAG_ENFORCING_ADMIN = "enforcing-admin";
         private static final String TAG_POLICY_SUM_SIZE = "policy-sum-size";
+        private static final String TAG_MAX_POLICY_SIZE_LIMIT = "max-policy-size-limit";
         private static final String ATTR_USER_ID = "user-id";
         private static final String ATTR_POLICY_SUM_SIZE = "size";
 
@@ -1805,6 +1832,7 @@
             writeGlobalPoliciesInner(serializer);
             writeEnforcingAdminsInner(serializer);
             writeEnforcingAdminSizeInner(serializer);
+            writeMaxPolicySizeInner(serializer);
         }
 
         private void writeLocalPoliciesInner(TypedXmlSerializer serializer) throws IOException {
@@ -1886,6 +1914,17 @@
             }
         }
 
+        private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)
+                throws IOException {
+            if (!devicePolicySizeTrackingEnabled()) {
+                return;
+            }
+            serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
+            serializer.attributeInt(
+                    /* namespace= */ null, ATTR_POLICY_SUM_SIZE, mPolicySizeLimit);
+            serializer.endTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
+        }
+
         void readFromFileLocked() {
             if (!mFile.exists()) {
                 Log.d(TAG, "" + mFile + " doesn't exist");
@@ -1926,6 +1965,9 @@
                     case TAG_ENFORCING_ADMIN_AND_SIZE:
                         readEnforcingAdminAndSizeInner(parser);
                         break;
+                    case TAG_MAX_POLICY_SIZE_LIMIT:
+                        readMaxPolicySizeInner(parser);
+                        break;
                     default:
                         Slogf.wtf(TAG, "Unknown tag " + tag);
                 }
@@ -2036,5 +2078,13 @@
             }
             mAdminPolicySize.get(admin.getUserId()).put(admin, size);
         }
+
+        private void readMaxPolicySizeInner(TypedXmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            if (!devicePolicySizeTrackingEnabled()) {
+                return;
+            }
+            mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 51eee64..9bf41f9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -101,6 +101,7 @@
 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
 import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
 import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
+import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
 import static android.app.admin.DeviceAdminInfo.USES_POLICY_FORCE_LOCK;
 import static android.app.admin.DeviceAdminInfo.USES_POLICY_WIPE_DATA;
 import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
@@ -237,6 +238,7 @@
 import static android.app.admin.flags.Flags.headlessDeviceOwnerSingleUserEnabled;
 import static android.app.admin.flags.Flags.policyEngineMigrationV2Enabled;
 import static android.app.admin.flags.Flags.assistContentUserRestrictionEnabled;
+import static android.app.admin.flags.Flags.securityLogV2Enabled;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -3376,9 +3378,10 @@
                     applyProfileRestrictionsIfDeviceOwnerLocked();
 
                     // TODO: Is this the right place to trigger the migration?
-                    if (shouldMigrateToDevicePolicyEngine()) {
-                        migratePoliciesToDevicePolicyEngine();
+                    if (shouldMigrateV1ToDevicePolicyEngine()) {
+                        migrateV1PoliciesToDevicePolicyEngine();
                     }
+                    migratePoliciesToPolicyEngineLocked();
                 }
                 maybeStartSecurityLogMonitorOnActivityManagerReady();
                 break;
@@ -3392,6 +3395,48 @@
         }
     }
 
+    @GuardedBy("getLockObject()")
+    private void maybeMigrateSecurityLoggingPolicyLocked() {
+        if (!securityLogV2Enabled() || mOwners.isSecurityLoggingMigrated()) {
+            return;
+        }
+
+        try {
+            migrateSecurityLoggingPolicyInternalLocked();
+        } catch (Exception e) {
+            Slog.e(LOG_TAG, "Failed to properly migrate security logging to policy engine", e);
+        }
+
+        Slog.i(LOG_TAG, "Marking security logging policy migration complete");
+        mOwners.markSecurityLoggingMigrated();
+    }
+
+    @GuardedBy("getLockObject()")
+    private void migrateSecurityLoggingPolicyInternalLocked() {
+        Slog.i(LOG_TAG, "Migrating security logging policy to policy engine");
+        if (!mInjector.securityLogGetLoggingEnabledProperty()) {
+            Slog.i(LOG_TAG, "Security logs not enabled, exiting");
+            return;
+        }
+
+        // Security logging can be enabled either by DO or by COPE PO.
+        final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
+        if (admin == null) {
+            Slog.wtf(LOG_TAG, "Security logging is enabled, but no appropriate admin found");
+            return;
+        }
+
+        EnforcingAdmin enforcingAdmin =
+                EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                        admin.info.getComponent(),
+                        admin.getUserHandle().getIdentifier(),
+                        admin);
+        mDevicePolicyEngine.setGlobalPolicy(
+                PolicyDefinition.SECURITY_LOGGING,
+                enforcingAdmin,
+                new BooleanPolicyValue(true));
+    }
+
     private void applyManagedSubscriptionsPolicyIfRequired() {
         int copeProfileUserId = getOrganizationOwnedProfileUserId();
         // This policy is relevant only for COPE devices.
@@ -9480,7 +9525,11 @@
 
     private int getHeadlessDeviceOwnerMode() {
         synchronized (getLockObject()) {
-            return getDeviceOwnerAdminLocked().info.getHeadlessDeviceOwnerMode();
+            ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+            if (deviceOwner == null) {
+                return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
+            }
+            return deviceOwner.info.getHeadlessDeviceOwnerMode();
         }
     }
 
@@ -11998,8 +12047,10 @@
         }
 
         if (packageList != null) {
-            for (String pkg : packageList) {
-                PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+            if (!devicePolicySizeTrackingEnabled()) {
+                for (String pkg : packageList) {
+                    PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+                }
             }
 
             List<InputMethodInfo> enabledImes = mInjector.binderWithCleanCallingIdentity(() ->
@@ -12235,17 +12286,18 @@
         }
         final CallerIdentity caller = getCallerIdentity(admin);
 
+        // Only allow the system user to use this method
+        Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
+                "createAndManageUser was called from non-system user");
+        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
+
         if (headlessDeviceOwnerSingleUserEnabled()) {
             // Block this method if the device is in headless main user mode
             Preconditions.checkCallAuthorization(
                     getHeadlessDeviceOwnerMode() != HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER,
                     "createAndManageUser was called while in headless single user mode");
         }
-        // Only allow the system user to use this method
-        Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
-                "createAndManageUser was called from non-system user");
-        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
-        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
 
         final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
         final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
@@ -14318,8 +14370,10 @@
     public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
             throws SecurityException {
         Objects.requireNonNull(packages, "packages is null");
-        for (String pkg : packages) {
-            PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+        if (!devicePolicySizeTrackingEnabled()) {
+            for (String pkg : packages) {
+                PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
+            }
         }
 
         CallerIdentity caller = getCallerIdentity(who, callerPackageName);
@@ -15721,6 +15775,11 @@
             return enforcingUsers;
         }
 
+        @Override
+        public void enforceSecurityLoggingPolicy(boolean enabled) {
+            enforceLoggingPolicy(enabled);
+        }
+
         private List<EnforcingUser> getEnforcingUsers(Set<EnforcingAdmin> admins) {
             List<EnforcingUser> enforcingUsers = new ArrayList();
             ComponentName deviceOwner = mOwners.getDeviceOwnerComponent();
@@ -15738,6 +15797,20 @@
         }
     }
 
+    private void enforceLoggingPolicy(boolean securityLoggingEnabled) {
+        Slogf.i(LOG_TAG, "Enforcing security logging, securityLoggingEnabled: %b",
+                securityLoggingEnabled);
+        SecurityLog.setLoggingEnabledProperty(securityLoggingEnabled);
+        if (securityLoggingEnabled) {
+            mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
+            synchronized (getLockObject()) {
+                maybePauseDeviceWideLoggingLocked();
+            }
+        } else {
+            mSecurityLogMonitor.stop();
+        }
+    }
+
     private Intent createShowAdminSupportIntent(int userId) {
         // This method is called with AMS lock held, so don't take DPMS lock
         final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
@@ -17586,19 +17659,32 @@
     }
 
     @Override
-    public void setSecurityLoggingEnabled(ComponentName admin, String packageName,
+    public void setSecurityLoggingEnabled(ComponentName who, String packageName,
             boolean enabled) {
         if (!mHasFeature) {
             return;
         }
-        final CallerIdentity caller = getCallerIdentity(admin, packageName);
+        final CallerIdentity caller = getCallerIdentity(who, packageName);
 
-        synchronized (getLockObject()) {
-            if (isPermissionCheckFlagEnabled()) {
-                enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
-                        UserHandle.USER_ALL);
+        if (securityLogV2Enabled()) {
+            EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+                    who,
+                    MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+                    caller.getPackageName(),
+                    caller.getUserId());
+            if (enabled) {
+                mDevicePolicyEngine.setGlobalPolicy(
+                        PolicyDefinition.SECURITY_LOGGING,
+                        admin,
+                        new BooleanPolicyValue(true));
             } else {
-                if (admin != null) {
+                mDevicePolicyEngine.removeGlobalPolicy(
+                        PolicyDefinition.SECURITY_LOGGING,
+                        admin);
+            }
+        } else {
+            synchronized (getLockObject()) {
+                if (who != null) {
                     Preconditions.checkCallAuthorization(
                             isProfileOwnerOfOrganizationOwnedDevice(caller)
                                     || isDefaultDeviceOwner(caller));
@@ -17607,17 +17693,17 @@
                     Preconditions.checkCallAuthorization(
                             isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
                 }
-            }
 
-            if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
-                return;
-            }
-            mInjector.securityLogSetLoggingEnabledProperty(enabled);
-            if (enabled) {
-                mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
-                maybePauseDeviceWideLoggingLocked();
-            } else {
-                mSecurityLogMonitor.stop();
+                if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
+                    return;
+                }
+                mInjector.securityLogSetLoggingEnabledProperty(enabled);
+                if (enabled) {
+                    mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
+                    maybePauseDeviceWideLoggingLocked();
+                } else {
+                    mSecurityLogMonitor.stop();
+                }
             }
         }
         DevicePolicyEventLogger
@@ -17633,26 +17719,36 @@
             return false;
         }
 
-        synchronized (getLockObject()) {
-            if (!isSystemUid(getCallerIdentity())) {
-                final CallerIdentity caller = getCallerIdentity(admin, packageName);
-                if (isPermissionCheckFlagEnabled()) {
-                    enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
-                            caller.getPackageName(), UserHandle.USER_ALL);
-                } else {
-                    if (admin != null) {
-                        Preconditions.checkCallAuthorization(
-                                isProfileOwnerOfOrganizationOwnedDevice(caller)
-                                        || isDefaultDeviceOwner(caller));
-                    } else {
-                        // A delegate app passes a null admin component, which is expected
-                        Preconditions.checkCallAuthorization(
-                                isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
-                    }
-                }
-            }
+        final CallerIdentity caller = getCallerIdentity(admin, packageName);
+        if (isSystemUid(caller)) {
+            // Settings uses this for privacy transparency.
+            // TODO: create a separate @hidden API for settings.
             return mInjector.securityLogGetLoggingEnabledProperty();
         }
+
+        if (securityLogV2Enabled()) {
+            final EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+                    admin,
+                    MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+                    caller.getPackageName(),
+                    caller.getUserId());
+            final Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+                    PolicyDefinition.SECURITY_LOGGING, enforcingAdmin);
+            return Boolean.TRUE.equals(policy);
+        } else {
+            synchronized (getLockObject()) {
+                if (admin != null) {
+                    Preconditions.checkCallAuthorization(
+                            isProfileOwnerOfOrganizationOwnedDevice(caller)
+                                    || isDefaultDeviceOwner(caller));
+                } else {
+                    // A delegate app passes a null admin component, which is expected
+                    Preconditions.checkCallAuthorization(
+                            isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+                }
+                return mInjector.securityLogGetLoggingEnabledProperty();
+            }
+        }
     }
 
     private void recordSecurityLogRetrievalTime() {
@@ -17727,17 +17823,32 @@
         }
 
         final CallerIdentity caller = getCallerIdentity(admin, packageName);
-        if (isPermissionCheckFlagEnabled()) {
-            Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
-                    || areAllUsersAffiliatedWithDeviceLocked());
 
-            enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
-                    UserHandle.USER_ALL);
+        if (securityLogV2Enabled()) {
+            EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+                    admin,
+                    MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+                    caller.getPackageName(),
+                    caller.getUserId());
+
+            synchronized (getLockObject()) {
+                Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+                        || areAllUsersAffiliatedWithDeviceLocked());
+            }
+
+            Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+                    PolicyDefinition.SECURITY_LOGGING, enforcingAdmin);
+
+            if (!Boolean.TRUE.equals(policy)) {
+                Slogf.e(LOG_TAG, "%s hasn't enabled security logging but tries to retrieve logs",
+                        caller.getPackageName());
+                return null;
+            }
         } else {
             if (admin != null) {
                 Preconditions.checkCallAuthorization(
                         isProfileOwnerOfOrganizationOwnedDevice(caller)
-                        || isDefaultDeviceOwner(caller));
+                                || isDefaultDeviceOwner(caller));
             } else {
                 // A delegate app passes a null admin component, which is expected
                 Preconditions.checkCallAuthorization(
@@ -17745,10 +17856,10 @@
             }
             Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
                     || areAllUsersAffiliatedWithDeviceLocked());
-        }
 
-        if (!mInjector.securityLogGetLoggingEnabledProperty()) {
-            return null;
+            if (!mInjector.securityLogGetLoggingEnabledProperty()) {
+                return null;
+            }
         }
 
         recordSecurityLogRetrievalTime();
@@ -17758,7 +17869,7 @@
                 .createEvent(DevicePolicyEnums.RETRIEVE_SECURITY_LOGS)
                 .setAdmin(caller.getPackageName())
                 .write();
-        return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
+        return logs != null ? new ParceledListSlice<>(logs) : null;
     }
 
     @Override
@@ -23477,10 +23588,10 @@
                 hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
         return mInjector.binderWithCleanCallingIdentity(() -> {
             boolean canForceMigration = forceMigration && !hasNonTestOnlyActiveAdmins();
-            if (!canForceMigration && !shouldMigrateToDevicePolicyEngine()) {
+            if (!canForceMigration && !shouldMigrateV1ToDevicePolicyEngine()) {
                 return false;
             }
-            return migratePoliciesToDevicePolicyEngine();
+            return migrateV1PoliciesToDevicePolicyEngine();
         });
     }
 
@@ -23503,14 +23614,15 @@
         });
     }
 
-    private boolean shouldMigrateToDevicePolicyEngine() {
+    private boolean shouldMigrateV1ToDevicePolicyEngine() {
         return mInjector.binderWithCleanCallingIdentity(() -> !mOwners.isMigratedToPolicyEngine());
     }
 
     /**
+     * Migrates the initial set of policies to use policy engine.
      * @return {@code true} if policies were migrated successfully, {@code false} otherwise.
      */
-    private boolean migratePoliciesToDevicePolicyEngine() {
+    private boolean migrateV1PoliciesToDevicePolicyEngine() {
         return mInjector.binderWithCleanCallingIdentity(() -> {
             try {
                 synchronized (getLockObject()) {
@@ -23537,6 +23649,14 @@
         });
     }
 
+    /**
+     * Migrates the rest of policies to use policy engine.
+     */
+    @GuardedBy("getLockObject()")
+    private void migratePoliciesToPolicyEngineLocked() {
+        maybeMigrateSecurityLoggingPolicyLocked();
+    }
+
     private void migrateAutoTimezonePolicy() {
         Slogf.i(LOG_TAG, "Skipping Migration of AUTO_TIMEZONE policy to device policy engine,"
                 + "as no way to identify if the value was set by the admin or the user.");
@@ -23965,5 +24085,30 @@
             }
             return adminOwnedSubscriptions;
         });
+
+    }
+
+    @Override
+    public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
+        if (!devicePolicySizeTrackingEnabled()) {
+            return;
+        }
+        CallerIdentity caller = getCallerIdentity(callerPackageName);
+        enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
+                caller.getUserId());
+
+        mDevicePolicyEngine.setMaxPolicyStorageLimit(storageLimit);
+    }
+
+    @Override
+    public int getMaxPolicyStorageLimit(String callerPackageName) {
+        if (!devicePolicySizeTrackingEnabled()) {
+            return -1;
+        }
+        CallerIdentity caller = getCallerIdentity(callerPackageName);
+        enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
+                caller.getUserId());
+
+        return mDevicePolicyEngine.getMaxPolicyStorageLimit();
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index bb275e45..c5a9888 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -616,6 +616,19 @@
         }
     }
 
+    void markSecurityLoggingMigrated() {
+        synchronized (mData) {
+            mData.mSecurityLoggingMigrated = true;
+            mData.writeDeviceOwner();
+        }
+    }
+
+    boolean isSecurityLoggingMigrated() {
+        synchronized (mData) {
+            return mData.mSecurityLoggingMigrated;
+        }
+    }
+
     @GuardedBy("mData")
     void pushToAppOpsLocked() {
         if (!mSystemReady) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 37d4f95..d9fef10 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -16,6 +16,7 @@
 package com.android.server.devicepolicy;
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.flags.Flags.securityLogV2Enabled;
 
 import android.annotation.Nullable;
 import android.app.admin.SystemUpdateInfo;
@@ -86,6 +87,7 @@
     private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
 
     private static final String ATTR_MIGRATED_TO_POLICY_ENGINE = "migratedToPolicyEngine";
+    private static final String ATTR_SECURITY_LOG_MIGRATED = "securityLogMigrated";
 
     // Internal state for the device owner package.
     OwnerInfo mDeviceOwner;
@@ -113,6 +115,7 @@
     private final PolicyPathProvider mPathProvider;
 
     boolean mMigratedToPolicyEngine = false;
+    boolean mSecurityLoggingMigrated = false;
 
     OwnersData(PolicyPathProvider pathProvider) {
         mPathProvider = pathProvider;
@@ -397,6 +400,9 @@
 
             out.startTag(null, TAG_POLICY_ENGINE_MIGRATION);
             out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine);
+            if (securityLogV2Enabled()) {
+                out.attributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, mSecurityLoggingMigrated);
+            }
             out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);
 
         }
@@ -457,6 +463,8 @@
                 case TAG_POLICY_ENGINE_MIGRATION:
                     mMigratedToPolicyEngine = parser.getAttributeBoolean(
                             null, ATTR_MIGRATED_TO_POLICY_ENGINE, false);
+                    mSecurityLoggingMigrated = securityLogV2Enabled()
+                            && parser.getAttributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, false);
                     break;
                 default:
                     Slog.e(TAG, "Unexpected tag: " + tag);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index b09908e..3474db3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -134,6 +134,13 @@
                         permissionName));
     }
 
+    static PolicyDefinition<Boolean> SECURITY_LOGGING = new PolicyDefinition<>(
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY),
+            TRUE_MORE_RESTRICTIVE,
+            POLICY_FLAG_GLOBAL_ONLY_POLICY,
+            PolicyEnforcerCallbacks::enforceSecurityLogging,
+            new BooleanPolicySerializer());
+
     static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
             new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
             new TopPriority<>(List.of(
@@ -356,6 +363,8 @@
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
                 GENERIC_PERMISSION_GRANT);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY,
+                SECURITY_LOGGING);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
                 USER_CONTROLLED_DISABLED_PACKAGES);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 506dbe8..4aaefa6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -21,6 +21,7 @@
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IntentFilterPolicyKey;
 import android.app.admin.LockTaskPolicy;
 import android.app.admin.PackagePermissionPolicyKey;
@@ -127,6 +128,14 @@
         }
     }
 
+    static boolean enforceSecurityLogging(
+            @Nullable Boolean value, @NonNull Context context, int userId,
+            @NonNull PolicyKey policyKey) {
+        final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
+        dpmi.enforceSecurityLoggingPolicy(Boolean.TRUE.equals(value));
+        return true;
+    }
+
     static boolean setLockTask(
             @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
         List<String> packages = Collections.emptyList();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 939a3dc..7a4454b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -101,6 +101,10 @@
     /** Minimum time between forced fetch attempts. */
     private static final long FORCE_FETCH_THROTTLE_NS = TimeUnit.SECONDS.toNanos(10);
 
+    /**
+     * Monitor thread is not null iff SecurityLogMonitor is running, i.e. started and not stopped.
+     * Pausing doesn't change it.
+     */
     @GuardedBy("mLock")
     private Thread mMonitorThread = null;
     @GuardedBy("mLock")
@@ -147,7 +151,6 @@
     void start(int enabledUser) {
         Slog.i(TAG, "Starting security logging for user " + enabledUser);
         mEnabledUser = enabledUser;
-        SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
         mLock.lock();
         try {
             if (mMonitorThread == null) {
@@ -160,6 +163,11 @@
 
                 mMonitorThread = new Thread(this);
                 mMonitorThread.start();
+
+                SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
+                Slog.i(TAG, "Security log monitor thread started");
+            } else {
+                Slog.i(TAG, "Security log monitor thread is already running");
             }
         } finally {
             mLock.unlock();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index d50affb..a0f2395 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -18,7 +18,6 @@
 import static android.content.pm.ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
 import static android.content.pm.ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
 import static android.content.pm.ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
-import static android.content.pm.ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
 
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull;
@@ -78,7 +77,6 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
@@ -4844,7 +4842,7 @@
         doReturn(expected != DISABLED_REASON_SIGNATURE_MISMATCH).when(
                 mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString());
 
-        assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk));
+        assertEquals(expected, spi.canRestoreTo(mService, pi, true));
     }
 
     public void testCanRestoreTo() {
@@ -4872,7 +4870,6 @@
         checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
         checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x", "y");
         checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
-        checkCanRestoreTo(DISABLED_REASON_VERSION_LOWER, spi1, false, 9, true, "sig1");
 
         // Any version okay.
         checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1");
@@ -5983,14 +5980,6 @@
         });
     }
 
-    public void testBackupAndRestore_publisherLowerVersion() {
-        prepareForBackupTest();
-
-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
-
-        checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_VERSION_LOWER);
-    }
-
     public void testBackupAndRestore_publisherWrongSignature() {
         prepareForBackupTest();
 
@@ -6626,252 +6615,6 @@
         });
     }
 
-
-    /**
-     * Restored to a lower version with no manifest shortcuts. All shortcuts are now invisible,
-     * and all calls from the publisher should ignore them.
-     */
-    public void testBackupAndRestore_disabledShortcutsAreIgnored() {
-        // Publish two manifest shortcuts.
-        addManifestShortcutResource(
-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
-                R.xml.shortcut_5_altalt);
-        updatePackageVersion(CALLING_PACKAGE_1, 1);
-        mService.mPackageMonitor.onReceive(mServiceContext,
-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
-
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcutWithShortLabel("s1", "original-title"),
-                    makeShortcut("s2"), makeShortcut("s3"))));
-        });
-
-        // Pin from launcher 1.
-        runWithCaller(LAUNCHER_1, USER_0, () -> {
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0);
-        });
-
-        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
-                any(byte[].class), anyString());
-
-        backupAndRestore();
-
-        // Lower the version and remove the manifest shortcuts.
-        addManifestShortcutResource(
-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
-                R.xml.shortcut_0);
-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
-
-        // When re-installing the app, the manifest shortcut should be re-published.
-        mService.mPackageMonitor.onReceive(mServiceContext,
-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
-        mService.mPackageMonitor.onReceive(mServiceContext,
-                genPackageAddIntent(LAUNCHER_1, USER_0));
-
-        // No shortcuts should be visible to the publisher.
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertWith(getCallerVisibleShortcuts())
-                    .isEmpty();
-        });
-
-        final Runnable checkAllDisabledForLauncher = () -> {
-            runWithCaller(LAUNCHER_1, USER_0, () -> {
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .areAllPinned()
-                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
-                        .areAllDisabled()
-                        .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_VERSION_LOWER)
-
-                        .forShortcutWithId("s1", si -> {
-                            assertEquals("original-title", si.getShortLabel());
-                        })
-                        .forShortcutWithId("ms1", si -> {
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title1 + "/en"
-                                    , si.getShortLabel());
-                        })
-                        .forShortcutWithId("ms2", si -> {
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title2 + "/en"
-                                    , si.getShortLabel());
-                        })
-                        .forShortcutWithId("ms3", si -> {
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title1 + "/en"
-                                    , si.getShortLabel());
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title2 + "/en"
-                                    , si.getLongLabel());
-                        })
-                        .forShortcutWithId("ms4", si -> {
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title2 + "/en"
-                                    , si.getShortLabel());
-                            assertEquals("string-com.android.test.1-user:0-res:"
-                                            + R.string.shortcut_title2 + "/en"
-                                    , si.getLongLabel());
-                        });
-            });
-        };
-
-        checkAllDisabledForLauncher.run();
-
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-
-            makeCallerForeground(); // CALLING_PACKAGE_1 is now in the foreground.
-
-            // All changing API calls should be ignored.
-
-            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
-            checkAllDisabledForLauncher.run();
-
-            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
-            checkAllDisabledForLauncher.run();
-
-            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
-            checkAllDisabledForLauncher.run();
-
-            getManager().removeAllDynamicShortcuts();
-            getManager().removeDynamicShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
-            checkAllDisabledForLauncher.run();
-
-            getManager().updateShortcuts(list(makeShortcutWithShortLabel("s1", "new-title")));
-            checkAllDisabledForLauncher.run();
-
-
-            // Add a shortcut -- even though ms1 was immutable, it will succeed.
-            assertTrue(getManager().addDynamicShortcuts(list(
-                    makeShortcutWithShortLabel("ms1", "original-title"))));
-
-            runWithCaller(LAUNCHER_1, USER_0, () -> {
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
-
-                        .selectByIds("ms1")
-                        .areAllEnabled()
-                        .areAllDynamic()
-                        .areAllPinned()
-                        .forAllShortcuts(si -> {
-                            assertEquals("original-title", si.getShortLabel());
-                        })
-
-                        // The rest still exist and disabled.
-                        .revertToOriginalList()
-                        .selectByIds("ms2", "ms3", "ms4", "s1", "s2")
-                        .areAllDisabled()
-                        .areAllPinned()
-                ;
-            });
-
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcutWithShortLabel("ms2", "new-title-2"))));
-
-            runWithCaller(LAUNCHER_1, USER_0, () -> {
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
-
-                        .selectByIds("ms1")
-                        .areAllEnabled()
-                        .areAllNotDynamic() // ms1 was not in the list, so no longer dynamic.
-                        .areAllPinned()
-                        .areAllMutable()
-                        .forAllShortcuts(si -> {
-                            assertEquals("original-title", si.getShortLabel());
-                        })
-
-                        .revertToOriginalList()
-                        .selectByIds("ms2")
-                        .areAllEnabled()
-                        .areAllDynamic()
-                        .areAllPinned()
-                        .areAllMutable()
-                        .forAllShortcuts(si -> {
-                            assertEquals("new-title-2", si.getShortLabel());
-                        })
-
-                        // The rest still exist and disabled.
-                        .revertToOriginalList()
-                        .selectByIds("ms3", "ms4", "s1", "s2")
-                        .areAllDisabled()
-                        .areAllPinned()
-                ;
-            });
-
-            // Prepare for requestPinShortcut().
-            setDefaultLauncher(USER_0, LAUNCHER_1);
-            mPinConfirmActivityFetcher = (packageName, userId) ->
-                    new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
-
-            mManager.requestPinShortcut(
-                    makeShortcutWithShortLabel("ms3", "new-title-3"),
-                    /*PendingIntent=*/ null);
-
-            // Note this was pinned, so it'll be accepted right away.
-            runWithCaller(LAUNCHER_1, USER_0, () -> {
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .selectByIds("ms3")
-                        .areAllEnabled()
-                        .areAllNotDynamic()
-                        .areAllPinned()
-                        .areAllMutable()
-                        .forAllShortcuts(si -> {
-                            assertEquals("new-title-3", si.getShortLabel());
-                            // The new one replaces the old manifest shortcut, so the long label
-                            // should be gone now.
-                            assertNull(si.getLongLabel());
-                        });
-            });
-
-            // Now, change the launcher to launcher2, and request pin again.
-            setDefaultLauncher(USER_0, LAUNCHER_2);
-
-            reset(mServiceContext);
-
-            assertTrue(mManager.isRequestPinShortcutSupported());
-            mManager.requestPinShortcut(
-                    makeShortcutWithShortLabel("ms4", "new-title-4"),
-                    /*PendingIntent=*/ null);
-
-            // Initially there should be no pinned shortcuts for L2.
-            runWithCaller(LAUNCHER_2, USER_0, () -> {
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .selectPinned()
-                        .isEmpty();
-
-                final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
-
-                verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
-
-                assertEquals(LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT,
-                        intent.getValue().getAction());
-                assertEquals(LAUNCHER_2, intent.getValue().getComponent().getPackageName());
-
-                // Check the request object.
-                final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
-
-                assertNotNull(request);
-                assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
-
-                assertWith(request.getShortcutInfo())
-                        .haveIds("ms4")
-                        .areAllOrphan()
-                        .forAllShortcuts(si -> {
-                            assertEquals("new-title-4", si.getShortLabel());
-                            // The new one replaces the old manifest shortcut, so the long label
-                            // should be gone now.
-                            assertNull(si.getLongLabel());
-                        });
-                assertTrue(request.accept());
-
-                assertWith(getShortcutAsLauncher(USER_0))
-                        .selectPinned()
-                        .haveIds("ms4")
-                        .areAllEnabled();
-            });
-        });
-    }
-
     /**
      * Test for restoring the pre-P backup format.
      */
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 5eb76e3..f077914 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -22,6 +22,9 @@
 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.Notification.FLAG_NO_CLEAR;
 import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 
 import static com.android.server.notification.GroupHelper.BASE_FLAGS;
@@ -81,6 +84,8 @@
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
+    private final int DEFAULT_VISIBILITY = VISIBILITY_PRIVATE;
+
     private @Mock GroupHelper.Callback mCallback;
     private @Mock PackageManager mPackageManager;
 
@@ -127,7 +132,7 @@
     }
 
     private NotificationAttributes getNotificationAttributes(int flags) {
-        return new NotificationAttributes(flags, mSmallIcon, COLOR_DEFAULT);
+        return new NotificationAttributes(flags, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY);
     }
 
     @Test
@@ -704,7 +709,8 @@
         final Icon icon = mock(Icon.class);
         when(icon.sameAs(icon)).thenReturn(true);
         final int iconColor = Color.BLUE;
-        final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor);
+        final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+                DEFAULT_VISIBILITY);
 
         // Add notifications with same icon and color
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
@@ -744,7 +750,7 @@
         doReturn(monochromeIcon).when(groupHelper).getMonochromeAppIcon(eq(pkg));
 
         final NotificationAttributes initialAttr = new NotificationAttributes(BASE_FLAGS,
-                initialIcon, initialIconColor);
+                initialIcon, initialIconColor, DEFAULT_VISIBILITY);
 
         // Add notifications with same icon and color
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
@@ -769,7 +775,42 @@
 
         // Summary should be updated to the default color and the icon to the monochrome icon
         NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, monochromeIcon,
-                COLOR_DEFAULT);
+                COLOR_DEFAULT, DEFAULT_VISIBILITY);
+        verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(newAttr));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+    public void testAddSummary_diffVisibility() {
+        final String pkg = "package";
+        final Icon icon = mock(Icon.class);
+        when(icon.sameAs(icon)).thenReturn(true);
+        final int iconColor = Color.BLUE;
+        final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+                VISIBILITY_PRIVATE);
+
+        // Add notifications with same icon and color and default visibility (private)
+        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+            StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null,
+                    icon, iconColor);
+            mGroupHelper.onNotificationPosted(sbn, false);
+        }
+        // Check that the summary has private visibility
+        verify(mCallback, times(1)).addAutoGroupSummary(
+                anyInt(), eq(pkg), anyString(), eq(attr));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+
+        // After auto-grouping, add new notification with public visibility
+        StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT,
+                String.valueOf(AUTOGROUP_AT_COUNT), UserHandle.SYSTEM, null, icon, iconColor);
+        sbn.getNotification().visibility = VISIBILITY_PUBLIC;
+        mGroupHelper.onNotificationPosted(sbn, true);
+
+        // Check that the summary visibility was updated
+        NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, icon, iconColor,
+                VISIBILITY_PUBLIC);
         verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(newAttr));
     }
 
@@ -781,7 +822,7 @@
         when(initialIcon.sameAs(initialIcon)).thenReturn(true);
         final int initialIconColor = Color.BLUE;
         final NotificationAttributes initialAttr = new NotificationAttributes(
-                GroupHelper.FLAG_INVALID, initialIcon, initialIconColor);
+                GroupHelper.FLAG_INVALID, initialIcon, initialIconColor, DEFAULT_VISIBILITY);
 
         // Add AUTOGROUP_AT_COUNT-1 notifications with same icon and color
         ArrayList<StatusBarNotification> notifications = new ArrayList<>();
@@ -817,11 +858,12 @@
         // Create notifications with the same icon
         List<NotificationAttributes> childrenAttr = new ArrayList<>();
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
-            childrenAttr.add(new NotificationAttributes(0, icon, COLOR_DEFAULT));
+            childrenAttr.add(new NotificationAttributes(0, icon, COLOR_DEFAULT,
+                    DEFAULT_VISIBILITY));
         }
 
         //Check that the generated summary icon is the same as the child notifications'
-        Icon summaryIcon = mGroupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+        Icon summaryIcon = mGroupHelper.getAutobundledSummaryAttributes(pkg, childrenAttr).icon;
         assertThat(summaryIcon).isEqualTo(icon);
     }
 
@@ -837,11 +879,12 @@
         // Create notifications with different icons
         List<NotificationAttributes> childrenAttr = new ArrayList<>();
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
-            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), COLOR_DEFAULT));
+            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), COLOR_DEFAULT,
+                    DEFAULT_VISIBILITY));
         }
 
         // Check that the generated summary icon is the monochrome icon
-        Icon summaryIcon = groupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+        Icon summaryIcon = groupHelper.getAutobundledSummaryAttributes(pkg, childrenAttr).icon;
         assertThat(summaryIcon).isEqualTo(monochromeIcon);
     }
 
@@ -853,11 +896,12 @@
         // Create notifications with the same icon color
         List<NotificationAttributes> childrenAttr = new ArrayList<>();
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
-            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor));
+            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+                    DEFAULT_VISIBILITY));
         }
 
         // Check that the generated summary icon color is the same as the child notifications'
-        int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+        int summaryIconColor = mGroupHelper.getAutobundledSummaryAttributes(pkg,
                 childrenAttr).iconColor;
         assertThat(summaryIconColor).isEqualTo(iconColor);
     }
@@ -869,17 +913,62 @@
         // Create notifications with different icon colors
         List<NotificationAttributes> childrenAttr = new ArrayList<>();
         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
-            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), i));
+            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), i,
+                    DEFAULT_VISIBILITY));
         }
 
         // Check that the generated summary icon color is the default color
-        int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+        int summaryIconColor = mGroupHelper.getAutobundledSummaryAttributes(pkg,
                 childrenAttr).iconColor;
         assertThat(summaryIconColor).isEqualTo(Notification.COLOR_DEFAULT);
     }
 
     @Test
     @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+    public void testAutobundledSummaryVisibility_hasPublicChildren() {
+        final String pkg = "package";
+        final int iconColor = Color.BLUE;
+        // Create notifications with private and public visibility
+        List<NotificationAttributes> childrenAttr = new ArrayList<>();
+        childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+                VISIBILITY_PUBLIC));
+        for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+                    VISIBILITY_PRIVATE));
+        }
+
+        // Check that the generated summary visibility is public
+        int summaryVisibility = mGroupHelper.getAutobundledSummaryAttributes(pkg,
+                childrenAttr).visibility;
+        assertThat(summaryVisibility).isEqualTo(VISIBILITY_PUBLIC);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+    public void testAutobundledSummaryVisibility_noPublicChildren() {
+        final String pkg = "package";
+        final int iconColor = Color.BLUE;
+        int visibility = VISIBILITY_PRIVATE;
+        // Create notifications with either private or secret visibility
+        List<NotificationAttributes> childrenAttr = new ArrayList<>();
+        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+            if (i % 2 == 0) {
+                visibility = VISIBILITY_PRIVATE;
+            } else {
+                visibility = VISIBILITY_SECRET;
+            }
+            childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor,
+                    visibility));
+        }
+
+        // Check that the generated summary visibility is private
+        int summaryVisibility = mGroupHelper.getAutobundledSummaryAttributes(pkg,
+                childrenAttr).visibility;
+        assertThat(summaryVisibility).isEqualTo(VISIBILITY_PRIVATE);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
     public void testMonochromeAppIcon_adaptiveIconExists() throws Exception {
         final String pkg = "testPackage";
         final int monochromeIconResId = 1234;
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 6aacfd7..94d24a9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -37,6 +37,7 @@
 import static android.app.Notification.FLAG_ONGOING_EVENT;
 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
+import static android.app.Notification.VISIBILITY_PRIVATE;
 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
@@ -2338,7 +2339,7 @@
 
         mService.updateAutobundledSummaryLocked(0, "pkg",
                 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
-                    mock(Icon.class), 0), false);
+                    mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
         waitForIdle();
 
         assertTrue(summary.getSbn().isOngoing());
@@ -2357,7 +2358,7 @@
 
         mService.updateAutobundledSummaryLocked(0, "pkg",
                 new NotificationAttributes(GroupHelper.BASE_FLAGS,
-                    mock(Icon.class), 0), false);
+                    mock(Icon.class), 0, VISIBILITY_PRIVATE), false);
         waitForIdle();
 
         assertFalse(summary.getSbn().isOngoing());
@@ -3479,7 +3480,8 @@
         when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
 
         NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
-                temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0);
+                temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0,
+                VISIBILITY_PRIVATE);
 
         assertThat(r.isImportanceFixed()).isTrue();
     }
@@ -12215,9 +12217,10 @@
         // grouphelper is a mock here, so make the calls it would make
 
         // add summary
-        mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(),
-                nr1.getSbn().getPackageName(), nr1.getKey(),
-                GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0));
+        mService.addNotification(
+                mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
+                    nr1.getKey(), GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0,
+                    VISIBILITY_PRIVATE));
 
         // cancel both children
         mBinderService.cancelNotificationWithTag(PKG, PKG, nr0.getSbn().getTag(),
@@ -12246,7 +12249,7 @@
         mService.addNotification(nr1);
         mService.addNotification(
                 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
-                nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
+                nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
 
         // add notifications + summary for USER_ALL
         NotificationRecord nr0_all =
@@ -12259,7 +12262,7 @@
         mService.addNotification(
                 mService.createAutoGroupSummary(nr0_all.getUserId(),
                 nr0_all.getSbn().getPackageName(),
-                nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
+                nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE));
 
         // cancel both children for USER_ALL
         mBinderService.cancelNotificationWithTag(PKG, PKG, nr0_all.getSbn().getTag(),
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 20a0850..368a96b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -73,6 +73,8 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SharedMemory;
+import android.service.voice.AlwaysOnHotwordDetector;
+import android.service.voice.HotwordAudioStream;
 import android.service.voice.HotwordDetectedResult;
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.HotwordDetectionServiceFailure;
@@ -81,6 +83,7 @@
 import android.service.voice.IDspHotwordDetectionCallback;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
 import android.service.voice.VisualQueryDetectionServiceFailure;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
 import android.text.TextUtils;
 import android.util.Pair;
 import android.util.Slog;
@@ -405,7 +408,83 @@
                 audioStream,
                 audioFormat,
                 options,
-                callback);
+                callback,
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ true);
+    }
+
+    void startListeningFromWearableLocked(
+            ParcelFileDescriptor audioStream,
+            AudioFormat audioFormat,
+            PersistableBundle options,
+            WearableHotwordDetectionCallback wearableCallback) {
+        if (DEBUG) {
+            Slog.d(TAG, "startListeningFromWearableLocked");
+        }
+        IMicrophoneHotwordDetectionVoiceInteractionCallback voiceInteractionCallback =
+                new IMicrophoneHotwordDetectionVoiceInteractionCallback() {
+                    @Override
+                    public void onDetected(
+                            HotwordDetectedResult hotwordDetectedResult,
+                            AudioFormat audioFormatFromCallback,
+                            ParcelFileDescriptor audioStreamFromCallback) {
+                        wearableCallback.onDetected();
+                        try {
+                            // This uses the DSP hotword code path to send the result to
+                            // AlwaysOnHotwordDetector. DSP trigger and wearable trigger operates
+                            // independently.
+                            mCallback.onKeyphraseDetectedFromExternalSource(hotwordDetectedResult);
+                        } catch (RemoteException ex) {
+                            Slog.w(
+                                    TAG,
+                                    "RemoteException when sending HotwordDetectedResult to"
+                                        + " VoiceInteractionService.",
+                                    ex);
+                            wearableCallback.onError(
+                                    "RemoteException when sending HotwordDetectedResult to"
+                                        + " VoiceInteractionService.");
+                            notifyOnDetectorRemoteException();
+                        }
+
+                        // Close the local copies of the file descriptors after sending them to
+                        // another process.
+                        for (HotwordAudioStream resultAudioStream :
+                                hotwordDetectedResult.getAudioStreams()) {
+                            try {
+                                resultAudioStream.getAudioStreamParcelFileDescriptor().close();
+                            } catch (IOException ex) {
+                                Slog.i(
+                                        TAG,
+                                        "Unable to close audio stream parcel file descriptor,",
+                                        ex);
+                            }
+                        }
+                    }
+
+                    @Override
+                    public void onHotwordDetectionServiceFailure(
+                            HotwordDetectionServiceFailure hotwordDetectionServiceFailure) {
+                        wearableCallback.onError(
+                                "onHotwordDetectionServiceFailure: "
+                                        + hotwordDetectionServiceFailure);
+                    }
+
+                    @Override
+                    public void onRejected(HotwordRejectedResult hotwordRejectedResult) {
+                        wearableCallback.onRejected();
+                    }
+
+                    @Override
+                    public IBinder asBinder() {
+                        // This callback will only be used locally within the same process.
+                        return null;
+                    }
+                };
+        handleExternalSourceHotwordDetectionLocked(
+                audioStream,
+                audioFormat,
+                options,
+                voiceInteractionCallback,
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ false);
     }
 
     @SuppressWarnings("GuardedBy")
@@ -413,7 +492,8 @@
             ParcelFileDescriptor audioStream,
             AudioFormat audioFormat,
             @Nullable PersistableBundle options,
-            IMicrophoneHotwordDetectionVoiceInteractionCallback callback) {
+            IMicrophoneHotwordDetectionVoiceInteractionCallback callback,
+            boolean shouldCloseAudioStreamWithDelayOnDetect) {
         if (DEBUG) {
             Slog.d(TAG, "#handleExternalSourceHotwordDetectionLocked");
         }
@@ -482,12 +562,22 @@
         // TODO: what if we cancelled and started a new one?
         mRemoteDetectionService.run(
                 service -> {
+                    PersistableBundle optionsToSend = options;
+                    if (android.app.wearable.Flags.enableHotwordWearableSensingApi()) {
+                        if (optionsToSend == null) {
+                            optionsToSend = new PersistableBundle();
+                        }
+                        optionsToSend.putBoolean(
+                                HotwordDetectionService
+                                        .KEY_SYSTEM_WILL_CLOSE_AUDIO_STREAM_AFTER_CALLBACK,
+                                shouldCloseAudioStreamWithDelayOnDetect);
+                    }
                     service.detectFromMicrophoneSource(
                             serviceAudioSource,
                             // TODO: consider making a proxy callback + copy of audio format
                             AUDIO_SOURCE_EXTERNAL,
                             audioFormat,
-                            options,
+                            optionsToSend,
                             new IDspHotwordDetectionCallback.Stub() {
                                 @Override
                                 public void onRejected(HotwordRejectedResult result)
@@ -530,18 +620,23 @@
                                                 getDetectorType(),
                                                 METRICS_EXTERNAL_SOURCE_DETECTED,
                                                 mVoiceInteractionServiceUid);
-                                        mScheduledExecutorService.schedule(
-                                                () -> {
-                                                    bestEffortClose(serviceAudioSink, audioSource);
-                                                },
-                                                EXTERNAL_HOTWORD_CLEANUP_MILLIS,
-                                                TimeUnit.MILLISECONDS);
-
+                                        if (shouldCloseAudioStreamWithDelayOnDetect) {
+                                            mScheduledExecutorService.schedule(
+                                                    () -> {
+                                                        bestEffortClose(
+                                                                serviceAudioSink, audioSource);
+                                                    },
+                                                    EXTERNAL_HOTWORD_CLEANUP_MILLIS,
+                                                    TimeUnit.MILLISECONDS);
+                                        }
                                         try {
                                             enforcePermissionsForDataDelivery();
                                         } catch (SecurityException e) {
-                                            Slog.w(TAG, "Ignoring #onDetected due to a "
-                                                    + "SecurityException", e);
+                                            Slog.w(
+                                                    TAG,
+                                                    "Ignoring #onDetected due to a "
+                                                            + "SecurityException",
+                                                    e);
                                             HotwordMetricsLogger.writeDetectorEvent(
                                                     getDetectorType(),
                                                     EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
@@ -560,11 +655,16 @@
                                         }
                                         HotwordDetectedResult newResult;
                                         try {
-                                            newResult = mHotwordAudioStreamCopier
-                                                    .startCopyingAudioStreams(triggerResult);
+                                            newResult =
+                                                    mHotwordAudioStreamCopier
+                                                            .startCopyingAudioStreams(
+                                                                    triggerResult);
                                         } catch (IOException e) {
-                                            Slog.w(TAG, "Ignoring #onDetected due to a "
-                                                    + "IOException", e);
+                                            Slog.w(
+                                                    TAG,
+                                                    "Ignoring #onDetected due to a "
+                                                            + "IOException",
+                                                    e);
                                             // TODO: Write event
                                             try {
                                                 callback.onHotwordDetectionServiceFailure(
@@ -578,7 +678,12 @@
                                             return;
                                         }
                                         try {
-                                            callback.onDetected(newResult, /* audioFormat= */ null,
+                                            // The ParcelFileDescriptors in newResult might be
+                                            // closed after this call. Parcelling newResult can
+                                            // throw an exception
+                                            callback.onDetected(
+                                                    newResult,
+                                                    /* audioFormat= */ null,
                                                     /* audioStream= */ null);
                                         } catch (RemoteException e) {
                                             notifyOnDetectorRemoteException();
@@ -588,8 +693,7 @@
                                                 + HotwordDetectedResult.getUsageSize(newResult)
                                                 + " bits from hotword trusted process");
                                         if (mDebugHotwordLogging) {
-                                            Slog.i(TAG,
-                                                    "Egressed detected result: " + newResult);
+                                            Slog.i(TAG, "Egressed detected result: " + newResult);
                                         }
                                     }
                                 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index cd390a1..f1f5458 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -63,6 +63,7 @@
 import android.service.voice.VisualQueryDetectionService;
 import android.service.voice.VisualQueryDetectionServiceFailure;
 import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
 import android.speech.IRecognitionServiceManager;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -451,6 +452,25 @@
         session.startListeningFromExternalSourceLocked(audioStream, audioFormat, options, callback);
     }
 
+    public void startListeningFromWearableLocked(
+            ParcelFileDescriptor audioStream,
+            AudioFormat audioFormat,
+            PersistableBundle options,
+            WearableHotwordDetectionCallback callback) {
+        if (DEBUG) {
+            Slog.d(TAG, "startListeningFromWearableLocked");
+        }
+        DetectorSession trustedSession = getDspTrustedHotwordDetectorSessionLocked();
+        if (trustedSession == null) {
+            callback.onError(
+                    "Unable to start listening from wearable because the trusted hotword detection"
+                            + " session is not available.");
+            return;
+        }
+        trustedSession.startListeningFromWearableLocked(
+                audioStream, audioFormat, options, callback);
+    }
+
     /**
      * This method is only used by SoftwareHotwordDetector.
      */
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4cdec70..ecb0f96 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.voiceinteraction;
 
+
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -74,6 +75,7 @@
 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.service.voice.VoiceInteractionSession;
@@ -319,6 +321,46 @@
             mServiceStub.mRoleObserver.onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT,
                                                 UserHandle.of(userId));
         }
+
+        @Override
+        public void startListeningFromWearable(
+                ParcelFileDescriptor audioStreamFromWearable,
+                AudioFormat audioFormatFromWearable,
+                PersistableBundle options,
+                ComponentName targetVisComponentName,
+                int userId,
+                WearableHotwordDetectionCallback callback) {
+            Slog.d(TAG, "#startListeningFromWearable");
+            VoiceInteractionManagerServiceImpl impl = mServiceStub.mImpl;
+            if (impl == null) {
+                callback.onError(
+                        "Unable to start listening from wearable because the service impl is"
+                                + " null.");
+                return;
+            }
+            if (targetVisComponentName != null && !targetVisComponentName.equals(impl.mComponent)) {
+                callback.onError(
+                        TextUtils.formatSimple(
+                                "Unable to start listening from wearable because the target"
+                                    + " VoiceInteractionService %s is different from the current"
+                                    + " VoiceInteractionService %s",
+                                targetVisComponentName, impl.mComponent));
+                return;
+            }
+            if (userId != impl.mUser) {
+                callback.onError(
+                        TextUtils.formatSimple(
+                                "Unable to start listening from wearable because the target userId"
+                                    + " %s is different from the current"
+                                    + " VoiceInteractionManagerServiceImpl's userId %s",
+                                userId, impl.mUser));
+                return;
+            }
+            synchronized (mServiceStub) {
+                impl.startListeningFromWearableLocked(
+                        audioStreamFromWearable, audioFormatFromWearable, options, callback);
+            }
+        }
     }
 
     // implementation entry point and binder service
@@ -1706,7 +1748,10 @@
                     if (keyphrase.equals(phrase.getText())) {
                         ArraySet<Locale> locales = new ArraySet<>();
                         locales.add(phrase.getLocale());
-                        return new KeyphraseMetadata(phrase.getId(), phrase.getText(), locales,
+                        return new KeyphraseMetadata(
+                                phrase.getId(),
+                                phrase.getText(),
+                                locales,
                                 phrase.getRecognitionModes());
                     }
                 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 7538142..84b36d5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -65,6 +65,7 @@
 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.system.OsConstants;
@@ -857,6 +858,24 @@
                 options, token, callback);
     }
 
+    public void startListeningFromWearableLocked(
+            ParcelFileDescriptor audioStream,
+            AudioFormat audioFormat,
+            PersistableBundle options,
+            WearableHotwordDetectionCallback callback) {
+        if (DEBUG) {
+            Slog.d(TAG, "startListeningFromWearable");
+        }
+        if (mHotwordDetectionConnection == null) {
+            callback.onError(
+                    "Unable to start listening from wearable because the hotword detection"
+                            + " connection is null.");
+            return;
+        }
+        mHotwordDetectionConnection.startListeningFromWearableLocked(
+                audioStream, audioFormat, options, callback);
+    }
+
     public void stopListeningFromMicLocked() {
         if (DEBUG) {
             Slog.d(TAG, "stopListeningFromMicLocked");
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
index c62db1ea..13b5f0d 100644
--- a/tests/Input/AndroidTest.xml
+++ b/tests/Input/AndroidTest.xml
@@ -4,6 +4,7 @@
  -->
 <configuration description="Runs Input Tests">
     <option name="test-tag" value="InputTests" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <!-- keeps the screen on during tests -->
         <option name="screen-always-on" value="on" />
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
index 14230fe..0fb4f90 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -42,6 +42,7 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.TextView;
+import android.window.InputTransferToken;
 
 public class EmbeddedWindowService extends Service {
     private static final String TAG = "EmbeddedWindowService";
@@ -118,7 +119,7 @@
 
         @Override
         public void attachEmbeddedSurfaceControl(SurfaceControl parentSc, int displayId,
-                IBinder hostToken) {
+                InputTransferToken inputTransferToken) {
             mHandler.post(() -> {
                 Paint paint = new Paint();
                 paint.setTextSize(40);
@@ -134,7 +135,7 @@
                 c.drawText("Remote", 250, 250, paint);
                 surface.unlockCanvasAndPost(c);
                 WindowManager wm = getSystemService(WindowManager.class);
-                wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+                wm.registerBatchedSurfaceControlInputReceiver(displayId, inputTransferToken,
                         mSurfaceControl,
                         Choreographer.getInstance(), event -> {
                             Log.d(TAG, "onInputEvent-remote " + event);
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
index 6b65b40e..e81f5f8 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
@@ -20,10 +20,12 @@
 import com.android.test.viewembed.IAttachEmbeddedWindowCallback;
 import android.view.WindowManager.LayoutParams;
 import android.view.SurfaceControl;
+import android.window.InputTransferToken;
 
 interface IAttachEmbeddedWindow {
     void attachEmbedded(IBinder hostToken, int width, int height, in IAttachEmbeddedWindowCallback callback);
     void relayout(in LayoutParams lp);
-    oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId, IBinder hostToken);
+    oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId,
+            in InputTransferToken inputTransferToken);
     oneway void tearDownEmbeddedSurfaceControl();
 }
\ No newline at end of file
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
index 7330ec1..e700bc2 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
@@ -139,7 +139,7 @@
         surface.unlockCanvasAndPost(c);
         WindowManager wm = getSystemService(WindowManager.class);
         wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
-                attachedSurfaceControl.getHostToken(), mLocalSurfaceControl,
+                attachedSurfaceControl.getInputTransferToken(), mLocalSurfaceControl,
                 Choreographer.getInstance(), event -> {
                     Log.d(TAG, "onInputEvent-sc " + event);
                     return false;
@@ -160,7 +160,8 @@
 
             WindowManager wm = getSystemService(WindowManager.class);
             wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
-                    mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(),
+                    mLocalSurfaceView.getRootSurfaceControl().getInputTransferToken(),
+                    mLocalSurfaceView.getSurfaceControl(),
                     Choreographer.getInstance(), event -> {
                         Log.d(TAG, "onInputEvent-local " + event);
                         return false;
@@ -210,7 +211,8 @@
         }
         try {
             mIAttachEmbeddedWindow.attachEmbeddedSurfaceControl(mParentSurfaceControl,
-                    getDisplayId(), mRemoteSurfaceView.getHostToken());
+                    getDisplayId(),
+                    mRemoteSurfaceView.getRootSurfaceControl().getInputTransferToken());
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to load embedded SurfaceControl", e);
         }
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index c6dd29c..30333da 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -54,6 +54,7 @@
 // This library is _not_ specific to Android APIs.
 java_library_host {
     name: "hoststubgen-helper-runtime",
+    defaults: ["ravenwood-internal-only-visibility-java"],
     srcs: [
         "helper-runtime-src/**/*.java",
     ],
@@ -64,11 +65,11 @@
         "guava",
     ],
     jarjar_rules: "jarjar-rules.txt",
-    visibility: ["//visibility:public"],
 }
 
 java_library {
     name: "hoststubgen-helper-runtime.ravenwood",
+    defaults: ["ravenwood-internal-only-visibility-java"],
     srcs: [
         "helper-runtime-src/**/*.java",
     ],
@@ -79,7 +80,6 @@
         "guava",
     ],
     jarjar_rules: "jarjar-rules.txt",
-    visibility: ["//visibility:public"],
 }
 
 // Host-side stub generator tool.
@@ -152,34 +152,3 @@
         "hoststubgen_dump.txt",
     ],
 }
-
-java_library_host {
-    name: "hoststubgen-helper-libcore-runtime",
-    srcs: [
-        "helper-framework-runtime-src/libcore-fake/**/*.java",
-    ],
-    visibility: ["//visibility:private"],
-}
-
-java_host_for_device {
-    name: "hoststubgen-helper-libcore-runtime.ravenwood",
-    libs: [
-        "hoststubgen-helper-libcore-runtime",
-    ],
-    visibility: ["//visibility:private"],
-}
-
-java_library {
-    name: "hoststubgen-helper-framework-runtime.ravenwood",
-    defaults: ["ravenwood-internal-only-visibility-java"],
-    srcs: [
-        "helper-framework-runtime-src/framework/**/*.java",
-    ],
-    libs: [
-        "hoststubgen-helper-runtime.ravenwood",
-        "framework-minus-apex.ravenwood",
-    ],
-    static_libs: [
-        "hoststubgen-helper-libcore-runtime.ravenwood",
-    ],
-}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 3c55237..ce856cd 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -25,6 +25,7 @@
 import java.io.FileInputStream
 import java.io.FileOutputStream
 import java.io.OutputStream
+import java.time.LocalDateTime
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.jar.JarOutputStream
@@ -42,6 +43,13 @@
         return source.contains(protoLogSimpleClassName)
     }
 
+    private fun zipEntry(path: String): ZipEntry {
+        val entry = ZipEntry(path)
+        // Use a constant time to improve the cachability of build actions.
+        entry.timeLocal = LocalDateTime.of(2008, 1, 1, 0, 0, 0)
+        return entry
+    }
+
     private fun processClasses(command: CommandOptions) {
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
@@ -77,7 +85,7 @@
                 }
             }.map { future ->
                 val (path, outSrc) = future.get()
-                outJar.putNextEntry(ZipEntry(path))
+                outJar.putNextEntry(zipEntry(path))
                 outJar.write(outSrc.toByteArray())
                 outJar.closeEntry()
             }
@@ -90,7 +98,7 @@
         val cachePackage = cacheSplit.dropLast(1).joinToString(".")
         val cachePath = "gen/${cacheSplit.joinToString("/")}.java"
 
-        outJar.putNextEntry(ZipEntry(cachePath))
+        outJar.putNextEntry(zipEntry(cachePath))
         outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
                 command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())