Merge "Clear calling identity before updating lock-task packages" into main
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 56fef1a..dab4110 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1486,13 +1486,13 @@
             AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
 
     /**
-     * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve the
+     * Allows the assistant app to get the training data from the PCC sandbox to improve the
      * hotword training model.
      *
      * @hide
      */
-    public static final int OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
-            AppProtoEnums.APP_OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO;
+    public static final int OP_RECEIVE_SANDBOX_TRAINING_DATA =
+            AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRAINING_DATA;
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1640,7 +1640,7 @@
             OPSTR_CAMERA_SANDBOXED,
             OPSTR_RECORD_AUDIO_SANDBOXED,
             OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
-            OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO
+            OPSTR_RECEIVE_SANDBOX_TRAINING_DATA
     })
     public @interface AppOpString {}
 
@@ -2261,13 +2261,13 @@
             "android:receive_sandbox_trigger_audio";
 
     /**
-     * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve
+     * Allows the assistant app to get the training data from the PCC sandbox to improve
      * the hotword training model.
      *
      * @hide
      */
-    public static final String OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
-            "android:receive_sandbox_negative_data_audio";
+    public static final String OPSTR_RECEIVE_SANDBOX_TRAINING_DATA =
+            "android:receive_sandbox_training_data";
 
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
@@ -2811,9 +2811,9 @@
                 OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                 "RECEIVE_SANDBOX_TRIGGER_AUDIO")
                 .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
-        new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
-                OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
-                "RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO").build()
+        new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRAINING_DATA,
+                OPSTR_RECEIVE_SANDBOX_TRAINING_DATA,
+                "RECEIVE_SANDBOX_TRAINING_DATA").build()
     };
 
     // The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d66fca8..ed0f872 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2495,7 +2495,8 @@
                     + ", hints=" + Arrays.toString(node.getAutofillHints())
                     + ", value=" + node.getAutofillValue()
                     + ", sanitized=" + node.isSanitized()
-                    + ", important=" + node.getImportantForAutofill());
+                    + ", important=" + node.getImportantForAutofill()
+                    + ", visibility=" + node.getVisibility());
         }
 
         final int NCHILDREN = node.getChildCount();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c7e5453..637770c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1307,9 +1307,9 @@
                     visibleFrame.intersect(mInsetsState.getDisplayFrame());
                     WindowInsets windowInsets = mInsetsState.calculateInsets(visibleFrame,
                             null /* ignoringVisibilityState */, config.isScreenRound(),
-                            false /* alwaysConsumeSystemBars */, mLayout.softInputMode,
-                            mLayout.flags, SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
-                            config.windowConfiguration.getWindowingMode(), null /* idSideMap */);
+                            mLayout.softInputMode, mLayout.flags, SYSTEM_UI_FLAG_VISIBLE,
+                            mLayout.type, config.windowConfiguration.getActivityType(),
+                            null /* idSideMap */);
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 85f5395..5fe2aa1 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -156,6 +156,13 @@
     public static final String SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS =
             "settings_biometrics2_fingerprint";
 
+    /**
+     * Flag to enable/disable remote auth enrollment and settings
+     * @hide
+     */
+    public static final String SETTINGS_REMOTEAUTH_ENROLLMENT_SETTINGS =
+            "settings_remoteauth_enrollment";
+
     /** Flag to enable/disable entire page in Accessibility -> Hearing aids
      *  @hide
      */
@@ -248,6 +255,8 @@
         DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true");
         DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false");
         DEFAULT_FLAGS.put("settings_press_hold_nav_handle_to_search", "false");
+        // TODO: b/298454866 Replace with Trunk Stable Feature Flag
+        DEFAULT_FLAGS.put(SETTINGS_REMOTEAUTH_ENROLLMENT_SETTINGS, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index fabfed3..1ec7c41 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.EventLogTags.IMF_IME_ANIM_CANCEL;
 import static android.view.EventLogTags.IMF_IME_ANIM_FINISH;
 import static android.view.EventLogTags.IMF_IME_ANIM_START;
@@ -39,6 +39,7 @@
 import static android.view.InsetsState.ISIDE_RIGHT;
 import static android.view.InsetsState.ISIDE_TOP;
 import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
 import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
@@ -62,7 +63,6 @@
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation.Bounds;
-import android.view.WindowManager.LayoutParams;
 import android.view.animation.Interpolator;
 import android.view.inputmethod.ImeTracker;
 
@@ -396,10 +396,9 @@
     private Insets getInsetsFromState(InsetsState state, Rect frame,
             @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
         return state.calculateInsets(frame, null /* ignoringVisibilityState */,
-                false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
-                LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
+                false /* isScreenRound */, SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode */,
                 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, idSideMap).getInsets(mTypes);
+                ACTIVITY_TYPE_UNDEFINED, idSideMap).getInsets(mTypes);
     }
 
     /** Computes the insets relative to the given frame. */
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8ec7d67..fb24211 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -652,7 +652,7 @@
     private int mLastLegacySoftInputMode;
     private int mLastLegacyWindowFlags;
     private int mLastLegacySystemUiFlags;
-    private int mLastWindowingMode;
+    private int mLastActivityType;
     private boolean mStartingAnimation;
     private int mCaptionInsetsHeight = 0;
     private int mImeCaptionBarInsetsHeight = 0;
@@ -800,10 +800,10 @@
                 }
             }
 
-            WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
-                    mLastInsets.isRound(), false /* alwaysConsumeSystemBars */,
+            WindowInsets insets = state.calculateInsets(mFrame,
+                    mState /* ignoringVisibilityState */, mLastInsets.isRound(),
                     mLastLegacySoftInputMode, mLastLegacyWindowFlags, mLastLegacySystemUiFlags,
-                    mWindowType, mLastWindowingMode, null /* idSideMap */);
+                    mWindowType, mLastActivityType, null /* idSideMap */);
             mHost.dispatchWindowInsetsAnimationProgress(insets,
                     Collections.unmodifiableList(runningAnimations));
             if (DEBUG) {
@@ -939,30 +939,29 @@
     }
 
     /**
-     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
-     *      int, android.util.SparseIntArray)
+     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, int, int, int, int, int,
+     *      android.util.SparseIntArray)
      */
     @VisibleForTesting
-    public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
-            int windowType, int windowingMode, int legacySoftInputMode, int legacyWindowFlags,
-            int legacySystemUiFlags) {
+    public WindowInsets calculateInsets(boolean isScreenRound, int windowType, int activityType,
+            int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
         mWindowType = windowType;
-        mLastWindowingMode = windowingMode;
+        mLastActivityType = activityType;
         mLastLegacySoftInputMode = legacySoftInputMode;
         mLastLegacyWindowFlags = legacyWindowFlags;
         mLastLegacySystemUiFlags = legacySystemUiFlags;
-        mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
-                isScreenRound, alwaysConsumeSystemBars, legacySoftInputMode, legacyWindowFlags,
-                legacySystemUiFlags, windowType, windowingMode, null /* idSideMap */);
+        mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState */,
+                isScreenRound, legacySoftInputMode, legacyWindowFlags,
+                legacySystemUiFlags, windowType, activityType, null /* idSideMap */);
         return mLastInsets;
     }
 
     /**
      * @see InsetsState#calculateVisibleInsets(Rect, int, int, int, int)
      */
-    public Insets calculateVisibleInsets(int windowType, int windowingMode,
+    public Insets calculateVisibleInsets(int windowType, int activityType,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
-        return mState.calculateVisibleInsets(mFrame, windowType, windowingMode, softInputMode,
+        return mState.calculateVisibleInsets(mFrame, windowType, activityType, softInputMode,
                 windowFlags);
     }
 
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index af24140..59e0932 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
 import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
 import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
@@ -39,7 +40,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.ActivityType;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -136,9 +137,8 @@
      * @return The calculated insets.
      */
     public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
-            boolean isScreenRound, boolean alwaysConsumeSystemBars,
-            int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
-            int windowType, @WindowConfiguration.WindowingMode int windowingMode,
+            boolean isScreenRound, int legacySoftInputMode, int legacyWindowFlags,
+            int legacySystemUiFlags, int windowType, @ActivityType int activityType,
             @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
         Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
@@ -185,9 +185,8 @@
         if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
             compatInsetsTypes &= ~statusBars();
         }
-        if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
-            // Clear all types but forceConsumingTypes.
-            compatInsetsTypes &= forceConsumingTypes;
+        if (clearsCompatInsets(windowType, legacyWindowFlags, activityType, forceConsumingTypes)) {
+            compatInsetsTypes = 0;
         }
 
         return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
@@ -295,26 +294,27 @@
         return insets;
     }
 
-    public Insets calculateVisibleInsets(Rect frame, int windowType, int windowingMode,
+    public Insets calculateVisibleInsets(Rect frame, int windowType, @ActivityType int activityType,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
-        final boolean clearsCompatInsets = clearsCompatInsets(
-                windowType, windowFlags, windowingMode);
         final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST;
         final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING
                 ? systemBars() | ime()
                 : systemBars();
+        @InsetsType int forceConsumingTypes = 0;
         Insets insets = Insets.NONE;
         for (int i = mSources.size() - 1; i >= 0; i--) {
             final InsetsSource source = mSources.valueAt(i);
             if ((source.getType() & visibleInsetsTypes) == 0) {
                 continue;
             }
-            if (clearsCompatInsets && !source.hasFlags(FLAG_FORCE_CONSUMING)) {
-                continue;
+            if (source.hasFlags(FLAG_FORCE_CONSUMING)) {
+                forceConsumingTypes |= source.getType();
             }
             insets = Insets.max(source.calculateVisibleInsets(frame), insets);
         }
-        return insets;
+        return clearsCompatInsets(windowType, windowFlags, activityType, forceConsumingTypes)
+                ? Insets.NONE
+                : insets;
     }
 
     /**
@@ -662,10 +662,15 @@
         mSources.put(source.getId(), source);
     }
 
-    public static boolean clearsCompatInsets(int windowType, int windowFlags, int windowingMode) {
+    public static boolean clearsCompatInsets(int windowType, int windowFlags,
+            @ActivityType int activityType, @InsetsType int forceConsumingTypes) {
         return (windowFlags & FLAG_LAYOUT_NO_LIMITS) != 0
+                // For compatibility reasons, this excludes the wallpaper, the system error windows,
+                // and the app windows while any system bar is forcibly consumed.
                 && windowType != TYPE_WALLPAPER && windowType != TYPE_SYSTEM_ERROR
-                && !WindowConfiguration.inMultiWindowMode(windowingMode);
+                // This ensures the app content won't be obscured by compat insets even if the app
+                // has FLAG_LAYOUT_NO_LIMITS.
+                && (forceConsumingTypes == 0 || activityType != ACTIVITY_TYPE_STANDARD);
     }
 
     public void dump(String prefix, PrintWriter pw) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e0fda7e..60d964e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2848,16 +2848,15 @@
         if (mLastWindowInsets == null || forceConstruct) {
             final Configuration config = getConfiguration();
             mLastWindowInsets = mInsetsController.calculateInsets(
-                    config.isScreenRound(), mAttachInfo.mAlwaysConsumeSystemBars,
-                    mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
-                    mWindowAttributes.softInputMode, mWindowAttributes.flags,
-                    (mWindowAttributes.systemUiVisibility
+                    config.isScreenRound(), mWindowAttributes.type,
+                    config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode,
+                    mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility
                             | mWindowAttributes.subtreeSystemUiVisibility));
 
             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
-                    mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
+                    mWindowAttributes.type, config.windowConfiguration.getActivityType(),
                     mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
         }
         return mLastWindowInsets;
diff --git a/core/java/android/window/WindowMetricsController.java b/core/java/android/window/WindowMetricsController.java
index 2858f0a..e32c8e5 100644
--- a/core/java/android/window/WindowMetricsController.java
+++ b/core/java/android/window/WindowMetricsController.java
@@ -16,7 +16,7 @@
 
 package android.window;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
@@ -80,7 +80,7 @@
         final Rect bounds;
         final float density;
         final boolean isScreenRound;
-        final int windowingMode;
+        final int activityType;
         synchronized (ResourcesManager.getInstance()) {
             final Configuration config = mContext.getResources().getConfiguration();
             final WindowConfiguration winConfig = config.windowConfiguration;
@@ -90,11 +90,11 @@
             // as DisplayMetrics#density
             density = config.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
             isScreenRound = config.isScreenRound();
-            windowingMode = winConfig.getWindowingMode();
+            activityType = winConfig.getActivityType();
         }
         final IBinder token = Context.getToken(mContext);
         final Supplier<WindowInsets> insetsSupplier = () -> getWindowInsetsFromServerForDisplay(
-                mContext.getDisplayId(), token, bounds, isScreenRound, windowingMode);
+                mContext.getDisplayId(), token, bounds, isScreenRound, activityType);
         return new WindowMetrics(new Rect(bounds), insetsSupplier, density);
     }
 
@@ -105,23 +105,22 @@
      * @param token the token of Activity or WindowContext
      * @param bounds the window bounds to calculate insets for
      * @param isScreenRound if the display identified by displayId is round
-     * @param windowingMode the windowing mode of the window to calculate insets for
+     * @param activityType the activity type of the window to calculate insets for
      * @return WindowInsets calculated for the given window bounds, on the given display
      */
     private static WindowInsets getWindowInsetsFromServerForDisplay(int displayId, IBinder token,
-            Rect bounds, boolean isScreenRound, int windowingMode) {
+            Rect bounds, boolean isScreenRound, int activityType) {
         try {
             final InsetsState insetsState = new InsetsState();
-            final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
-                    .getWindowInsets(displayId, token, insetsState);
+            WindowManagerGlobal.getWindowManagerService().getWindowInsets(
+                    displayId, token, insetsState);
             final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale();
             if (overrideInvScale != 1f) {
                 insetsState.scale(overrideInvScale);
             }
             return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState */,
-                    isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING,
-                    0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
-                    WindowManager.LayoutParams.INVALID_WINDOW_TYPE, windowingMode,
+                    isScreenRound, SOFT_INPUT_ADJUST_NOTHING, 0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
+                    WindowManager.LayoutParams.INVALID_WINDOW_TYPE, activityType,
                     null /* idSideMap */);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -157,7 +156,7 @@
                     currentDisplayInfo.displayId, null /* token */,
                     new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                             currentDisplayInfo.getNaturalHeight()), isScreenRound,
-                    WINDOWING_MODE_FULLSCREEN);
+                    ACTIVITY_TYPE_UNDEFINED);
             // Set the hardware-provided insets.
             windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
                             currentDisplayInfo.roundedCorners)
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index bb86801..86ca077 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1113,15 +1113,14 @@
             if (insets != null) {
                 mLastForceConsumingTypes = insets.getForceConsumingTypes();
 
-                @InsetsType int compatInsetsTypes =
+                final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
+                        getResources().getConfiguration().windowConfiguration.getActivityType(),
+                        mLastForceConsumingTypes);
+                final @InsetsType int compatInsetsTypes =
                         WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout();
-                if (clearsCompatInsets(attrs.type, attrs.flags,
-                        getResources().getConfiguration().windowConfiguration.getWindowingMode())) {
-                    compatInsetsTypes &= mLastForceConsumingTypes;
-                }
                 final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
                         WindowInsets.Type.systemBars());
-                final Insets systemInsets = compatInsetsTypes == 0
+                final Insets systemInsets = clearsCompatInsets
                         ? Insets.NONE
                         : Insets.min(insets.getInsets(compatInsetsTypes), stableBarInsets);
                 mLastTopInset = systemInsets.top;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a72f779..7bfc7de 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1185,6 +1185,9 @@
     -->
     <integer name="config_shortPressOnSleepBehavior">0</integer>
 
+    <!-- Whether to silence telephony ringer on sleep key event -->
+    <bool name="config_silenceRingerOnSleepKey">false</bool>
+
     <!-- Control the behavior when the user long presses the stem primary button.
          Stem primary button is only used on watch form factor. If a device is not
          a watch, setting this config is no-op.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ee0563b..c903e33 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -464,6 +464,7 @@
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
+  <java-symbol type="bool" name="config_silenceRingerOnSleepKey" />
   <java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" />
   <java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" />
   <java-symbol type="string" name="config_primaryShortPressTargetActivity" />
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index f45db23..8c93fbb 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -81,8 +81,7 @@
                     Insets.of(10, 10, 10, 10), rect, rect, rect, rect));
             mController.calculateInsets(
                     false,
-                    false,
-                    TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                    TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                     SOFT_INPUT_ADJUST_RESIZE, 0, 0);
             mImeConsumer = mController.getImeSourceConsumer();
         });
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index b8f0d5c..1568174 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
@@ -171,8 +171,7 @@
             mController.onStateChanged(state);
             mController.calculateInsets(
                     false,
-                    false,
-                    TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                    TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                     SOFT_INPUT_ADJUST_RESIZE, 0, 0);
             mController.onFrameChanged(new Rect(0, 0, 100, 100));
         });
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index b06cd39..906d84e 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -16,8 +16,9 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.InsetsState.ISIDE_BOTTOM;
 import static android.view.InsetsState.ISIDE_TOP;
@@ -101,7 +102,7 @@
                 .setVisible(true);
         SparseIntArray typeSideMap = new SparseIntArray();
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 typeSideMap);
         assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
@@ -120,7 +121,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 null);
         assertEquals(100, insets.getStableInsetBottom());
         assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(systemBars()));
@@ -139,7 +140,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -154,7 +155,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -169,7 +170,7 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
         assertEquals(100, insets.getInsets(ime()).bottom);
@@ -185,12 +186,12 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
-        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
                 SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
     }
 
@@ -200,12 +201,12 @@
                 .setFrame(new Rect(0, 0, 100, 100))
                 .setVisible(false);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
-                TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
+                TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
-        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
                 SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
     }
 
@@ -213,22 +214,23 @@
     public void testCalculateInsets_flagLayoutNoLimits() {
         mState.getOrCreateSource(ID_STATUS_BAR, statusBars())
                 .setFrame(new Rect(0, 0, 100, 100))
-                .setVisible(true);
+                .setVisible(true)
+                .setFlags(FLAG_FORCE_CONSUMING);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_WALLPAPER, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_WALLPAPER, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_FREEFORM, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_APPLICATION, ACTIVITY_TYPE_STANDARD, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
     }
 
@@ -243,7 +245,7 @@
                 .setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 400), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
@@ -255,7 +257,7 @@
                 .setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 150, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 150, 400), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
@@ -269,7 +271,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -284,7 +286,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -292,11 +294,11 @@
 
     @Test
     public void testCalculateInsets_emptyIme() {
-        WindowInsets insets1 = mState.calculateInsets(new Rect(), null, false, false,
-                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets1 = mState.calculateInsets(new Rect(), null, false,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         mState.getOrCreateSource(ID_IME, ime());
-        WindowInsets insets2 = mState.calculateInsets(new Rect(), null, false, false,
-                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets2 = mState.calculateInsets(new Rect(), null, false,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.NONE, insets1.getInsets(ime()));
         assertEquals(Insets.NONE, insets2.getInsets(ime()));
         assertEquals(insets1, insets2);
@@ -311,8 +313,8 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         mState.removeSource(ID_IME);
-        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
-                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
     }
 
@@ -527,7 +529,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_PAN, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
     }
@@ -546,7 +548,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
     }
@@ -565,7 +567,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_PAN, FLAG_LAYOUT_NO_LIMITS);
         assertEquals(Insets.NONE, visibleInsets);
     }
@@ -599,8 +601,8 @@
                 new Rect(0, 0, 1, 2),
                 new Rect(197, 296, 200, 300),
                 new Rect(197, 296, 200, 300)));
-        DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false, false,
-                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+        DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false,
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 new SparseIntArray()).getDisplayCutout();
         assertEquals(0, cutout.getSafeInsetLeft());
         assertEquals(1, cutout.getSafeInsetTop());
@@ -625,8 +627,8 @@
                 new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380),
                 new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380)));
         WindowInsets windowInsets = mState.calculateInsets(new Rect(1, 2, 197, 396), null, false,
-                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, new SparseIntArray());
         assertEquals(new RoundedCorner(POSITION_TOP_LEFT, 10, 9, 8),
                 windowInsets.getRoundedCorner(POSITION_TOP_LEFT));
         assertEquals(new RoundedCorner(POSITION_TOP_RIGHT, 10, 189, 8),
@@ -642,8 +644,8 @@
         mState.setDisplayFrame(new Rect(0, 0, 200, 400));
         mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
         WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
-                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, new SparseIntArray());
 
         final DisplayShape expect =
                 DisplayShape.createDefaultDisplayShape(200, 400, false).setOffset(-10, -20);
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index eb650ca..434b008 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -126,7 +126,6 @@
         "flickertestapplib",
         "flickerlib",
         "flickerlib-helpers",
-        "flickerlib-trace_processor_shell",
         "platform-test-annotations",
         "wm-flicker-common-app-helpers",
         "wm-flicker-common-assertions",
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
index ae130b8..6a87de4 100644
--- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
@@ -45,13 +45,9 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <!-- Enable bubble notification-->
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
-    <!-- Allow the test to connect to perfetto trace processor -->
-    <uses-permission android:name="android.permission.INTERNET"/>
 
-    <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
-    <application android:requestLegacyExternalStorage="true"
-                 android:networkSecurityConfig="@xml/network_security_config"
-                 android:largeHeap="true">
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <application android:requestLegacyExternalStorage="true" android:largeHeap="true">
         <uses-library android:name="android.test.runner"/>
 
         <service android:name=".NotificationListener"
diff --git a/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml
deleted file mode 100644
index 4bd9ca0..0000000
--- a/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">localhost</domain>
-    </domain-config>
-</network-security-config>
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index e7bbf97..f68078a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -22,6 +22,7 @@
 import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
 import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
 import android.os.Handler
+import android.os.Trace
 import android.util.Log
 import android.view.Display
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -34,9 +35,14 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 
 /** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
@@ -49,7 +55,25 @@
      *
      * When `null`, it means there is no pending display waiting to be enabled.
      */
-    val pendingDisplayId: Flow<Int?>
+    val pendingDisplay: Flow<PendingDisplay?>
+
+    /** Represents a connected display that has not been enabled yet. */
+    interface PendingDisplay {
+        /** Id of the pending display. */
+        val id: Int
+
+        /** Enables the display, making it available to the system. */
+        suspend fun enable()
+
+        /**
+         * Ignores the pending display. When called, this specific display id doesn't appear as
+         * pending anymore until the display is disconnected and reconnected again.
+         */
+        suspend fun ignore()
+
+        /** Disables the display, making it unavailable to the system. */
+        suspend fun disable()
+    }
 }
 
 @SysUISingleton
@@ -62,7 +86,8 @@
     @Background backgroundCoroutineDispatcher: CoroutineDispatcher
 ) : DisplayRepository {
 
-    override val displays: Flow<Set<Display>> =
+    // Displays are enabled only after receiving them in [onDisplayAdded]
+    private val enabledDisplays: StateFlow<Set<Display>> =
         conflatedCallbackFlow {
                 val callback =
                     object : DisplayListener {
@@ -99,27 +124,38 @@
             displayManager.displays?.toSet() ?: emptySet()
         }
 
-    override val pendingDisplayId: Flow<Int?> =
+    /** Propagate to the listeners only enabled displays */
+    override val displays: Flow<Set<Display>> = enabledDisplays
+
+    private val enabledDisplayIds: Flow<Set<Int>> =
+        enabledDisplays
+            .map { enabledDisplaysSet -> enabledDisplaysSet.map { it.displayId }.toSet() }
+            .debugLog("enabledDisplayIds")
+
+    private val ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
+
+    /* keeps connected displays until they are disconnected. */
+    private val connectedDisplayIds: StateFlow<Set<Int>> =
         conflatedCallbackFlow {
                 val callback =
                     object : DisplayConnectionListener {
-                        private val pendingIds = mutableSetOf<Int>()
+                        private val connectedIds = mutableSetOf<Int>()
                         override fun onDisplayConnected(id: Int) {
-                            pendingIds += id
-                            trySend(id)
+                            if (DEBUG) {
+                                Log.d(TAG, "$id connected")
+                            }
+                            connectedIds += id
+                            ignoredDisplayIds.value -= id
+                            trySend(connectedIds.toSet())
                         }
 
                         override fun onDisplayDisconnected(id: Int) {
-                            if (id in pendingIds) {
-                                pendingIds -= id
-                                trySend(null)
-                            } else {
-                                Log.e(
-                                    TAG,
-                                    "onDisplayDisconnected received for unknown display. " +
-                                        "id=$id, knownIds=$pendingIds"
-                                )
+                            connectedIds -= id
+                            if (DEBUG) {
+                                Log.d(TAG, "$id disconnected. Connected ids: $connectedIds")
                             }
+                            ignoredDisplayIds.value -= id
+                            trySend(connectedIds.toSet())
                         }
                     }
                 displayManager.registerDisplayListener(
@@ -130,15 +166,80 @@
                 awaitClose { displayManager.unregisterDisplayListener(callback) }
             }
             .distinctUntilChanged()
+            .debugLog("connectedDisplayIds")
             .flowOn(backgroundCoroutineDispatcher)
             .stateIn(
                 applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = null
+                initialValue = emptySet()
             )
 
+    /**
+     * Pending displays are the ones connected, but not enabled and not ignored. A connected display
+     * is ignored after the user makes the decision to use it or not. For now, the initial decision
+     * from the user is final and not reversible.
+     */
+    private val pendingDisplayIds: Flow<Set<Int>> =
+        combine(enabledDisplayIds, connectedDisplayIds, ignoredDisplayIds) {
+                enabledDisplaysIds,
+                connectedDisplayIds,
+                ignoredDisplayIds ->
+                if (DEBUG) {
+                    Log.d(
+                        TAG,
+                        "combining enabled: $enabledDisplaysIds, " +
+                            "connected: $connectedDisplayIds, ignored: $ignoredDisplayIds"
+                    )
+                }
+                connectedDisplayIds - enabledDisplaysIds - ignoredDisplayIds
+            }
+            .debugLog("pendingDisplayIds")
+
+    override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?> =
+        pendingDisplayIds
+            .map { pendingDisplayIds ->
+                val id = pendingDisplayIds.maxOrNull() ?: return@map null
+                object : DisplayRepository.PendingDisplay {
+                    override val id = id
+                    override suspend fun enable() {
+                        traceSection("DisplayRepository#enable($id)") {
+                            displayManager.enableConnectedDisplay(id)
+                        }
+                        // After the display has been enabled, it is automatically ignored.
+                        ignore()
+                    }
+
+                    override suspend fun ignore() {
+                        traceSection("DisplayRepository#ignore($id)") {
+                            ignoredDisplayIds.value += id
+                        }
+                    }
+
+                    override suspend fun disable() {
+                        ignore()
+                        traceSection("DisplayRepository#disable($id)") {
+                            displayManager.disableConnectedDisplay(id)
+                        }
+                    }
+                }
+            }
+            .debugLog("pendingDisplay")
+
+    private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {
+        return if (DEBUG) {
+            this.onEach {
+                Log.d(TAG, "$flowName: $it")
+                Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, "$TAG#$flowName", 0)
+                Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, "$TAG#$flowName", "$it", 0)
+            }
+        } else {
+            this
+        }
+    }
+
     private companion object {
         const val TAG = "DisplayRepository"
+        val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
index ef6fa26..11ed96d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -16,14 +16,12 @@
 
 package com.android.systemui.display.domain.interactor
 
-import android.hardware.display.DisplayManager
 import android.view.Display
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import com.android.systemui.util.traceSection
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -52,13 +50,18 @@
         CONNECTED_SECURE,
     }
 
-    /** Represents a connected display that has not been enabled yet. */
+    /** Represents a connected display that has not been enabled yet for the UI layer. */
     interface PendingDisplay {
         /** Enables the display, making it available to the system. */
-        fun enable()
+        suspend fun enable()
 
-        /** Disables the display, making it unavailable to the system. */
-        fun disable()
+        /**
+         * Ignores the pending display.
+         *
+         * When called, this specific display id doesn't appear as pending anymore until the display
+         * is disconnected and reconnected again.
+         */
+        suspend fun ignore()
     }
 }
 
@@ -66,7 +69,6 @@
 class ConnectedDisplayInteractorImpl
 @Inject
 constructor(
-    private val displayManager: DisplayManager,
     keyguardRepository: KeyguardRepository,
     displayRepository: DisplayRepository,
 ) : ConnectedDisplayInteractor {
@@ -92,28 +94,19 @@
 
     // Provides the pending display only if the lockscreen is unlocked
     override val pendingDisplay: Flow<PendingDisplay?> =
-        displayRepository.pendingDisplayId.combine(keyguardRepository.isKeyguardUnlocked) {
-            pendingDisplayId,
-            keyguardUnlocked ->
-            if (pendingDisplayId != null && keyguardUnlocked) {
-                pendingDisplayId.toPendingDisplay()
+        displayRepository.pendingDisplay.combine(keyguardRepository.isKeyguardShowing) {
+            repositoryPendingDisplay,
+            keyguardShowing ->
+            if (repositoryPendingDisplay != null && !keyguardShowing) {
+                repositoryPendingDisplay.toInteractorPendingDisplay()
             } else {
                 null
             }
         }
 
-    private fun Int.toPendingDisplay() =
+    private fun DisplayRepository.PendingDisplay.toInteractorPendingDisplay(): PendingDisplay =
         object : PendingDisplay {
-            val id = this@toPendingDisplay
-            override fun enable() {
-                traceSection("DisplayRepository#enable($id)") {
-                    displayManager.enableConnectedDisplay(id)
-                }
-            }
-            override fun disable() {
-                traceSection("DisplayRepository#enable($id)") {
-                    displayManager.disableConnectedDisplay(id)
-                }
-            }
+            override suspend fun enable() = this@toInteractorPendingDisplay.enable()
+            override suspend fun ignore() = this@toInteractorPendingDisplay.ignore()
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index 174c6ff..ecc9d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -24,15 +24,22 @@
 import android.widget.TextView
 import com.android.systemui.R
 
-/** Dialog used to decide what to do with a connected display. */
+/**
+ * Dialog used to decide what to do with a connected display.
+ *
+ * [onCancelMirroring] is called **only** if mirroring didn't start, or when the dismiss button is
+ * pressed.
+ */
 class MirroringConfirmationDialog(
     context: Context,
     private val onStartMirroringClickListener: View.OnClickListener,
-    private val onDismissClickListener: View.OnClickListener,
+    private val onCancelMirroring: View.OnClickListener,
 ) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
 
     private lateinit var mirrorButton: TextView
     private lateinit var dismissButton: TextView
+    private var enabledPressed = false
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         window?.apply {
@@ -45,10 +52,15 @@
         mirrorButton =
             requireViewById<TextView>(R.id.enable_display).apply {
                 setOnClickListener(onStartMirroringClickListener)
+                enabledPressed = true
             }
         dismissButton =
-            requireViewById<TextView>(R.id.cancel).apply {
-                setOnClickListener(onDismissClickListener)
+            requireViewById<TextView>(R.id.cancel).apply { setOnClickListener(onCancelMirroring) }
+
+        setOnDismissListener {
+            if (!enabledPressed) {
+                onCancelMirroring.onClick(null)
             }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index ece33b7..86ef439 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -19,13 +19,16 @@
 import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.ui.view.MirroringConfirmationDialog
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
 
 /**
  * Shows/hides a dialog to allow the user to decide whether to use the external display for
@@ -38,6 +41,7 @@
     private val context: Context,
     private val connectedDisplayInteractor: ConnectedDisplayInteractor,
     @Application private val scope: CoroutineScope,
+    @Background private val bgDispatcher: CoroutineDispatcher
 ) {
 
     private var dialog: Dialog? = null
@@ -61,10 +65,13 @@
             MirroringConfirmationDialog(
                     context,
                     onStartMirroringClickListener = {
-                        pendingDisplay.enable()
+                        scope.launch(bgDispatcher) { pendingDisplay.enable() }
                         hideDialog()
                     },
-                    onDismissClickListener = { hideDialog() }
+                    onCancelMirroring = {
+                        scope.launch(bgDispatcher) { pendingDisplay.ignore() }
+                        hideDialog()
+                    }
                 )
                 .apply { show() }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 6bc9abf..257006e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -126,11 +126,11 @@
         }
 
     override fun start() {
+        bindKeyguardRootView()
         if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) {
             keyguardRootView.removeAllViews()
             initializeViews()
         } else {
-            bindKeyguardRootView()
             val notificationPanel =
                 notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup
             unbindKeyguardBottomArea(notificationPanel)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index db7c003..4bd380e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -52,6 +52,7 @@
 
     private val displayManager = mock<DisplayManager>()
     private val displayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
+    private val connectedDisplayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
 
     private val testHandler = FakeHandler(Looper.getMainLooper())
     private val testScope = TestScope(UnconfinedTestDispatcher())
@@ -114,7 +115,7 @@
 
             // Let's make sure it has *NOT* been unregistered, as there is still a subscriber.
             setDisplays(1)
-            displayListener.value.onDisplayAdded(1)
+            sendOnDisplayAdded(1)
             assertThat(firstSubscriber?.ids()).containsExactly(1)
         }
 
@@ -127,7 +128,7 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1)
-            displayListener.value.onDisplayAdded(1)
+            sendOnDisplayAdded(1)
 
             assertThat(value?.ids()).containsExactly(1)
         }
@@ -138,13 +139,13 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1, 2, 3, 4)
-            displayListener.value.onDisplayAdded(1)
-            displayListener.value.onDisplayAdded(2)
-            displayListener.value.onDisplayAdded(3)
-            displayListener.value.onDisplayAdded(4)
+            sendOnDisplayAdded(1)
+            sendOnDisplayAdded(2)
+            sendOnDisplayAdded(3)
+            sendOnDisplayAdded(4)
 
             setDisplays(1, 2, 3)
-            displayListener.value.onDisplayRemoved(4)
+            sendOnDisplayRemoved(4)
 
             assertThat(value?.ids()).containsExactly(1, 2, 3)
         }
@@ -155,10 +156,10 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1, 2, 3, 4)
-            displayListener.value.onDisplayAdded(1)
-            displayListener.value.onDisplayAdded(2)
-            displayListener.value.onDisplayAdded(3)
-            displayListener.value.onDisplayAdded(4)
+            sendOnDisplayAdded(1)
+            sendOnDisplayAdded(2)
+            sendOnDisplayAdded(3)
+            sendOnDisplayAdded(4)
 
             displayListener.value.onDisplayChanged(4)
 
@@ -168,22 +169,22 @@
     @Test
     fun onDisplayConnected_pendingDisplayReceived() =
         testScope.runTest {
-            val pendingDisplay by latestPendingDisplayFlowValue()
+            val pendingDisplay by lastPendingDisplay()
 
-            displayListener.value.onDisplayConnected(1)
+            sendOnDisplayConnected(1)
 
-            assertThat(pendingDisplay).isEqualTo(1)
+            assertThat(pendingDisplay!!.id).isEqualTo(1)
         }
 
     @Test
     fun onDisplayDisconnected_pendingDisplayNull() =
         testScope.runTest {
-            val pendingDisplay by latestPendingDisplayFlowValue()
-            displayListener.value.onDisplayConnected(1)
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
 
             assertThat(pendingDisplay).isNotNull()
 
-            displayListener.value.onDisplayDisconnected(1)
+            sendOnDisplayDisconnected(1)
 
             assertThat(pendingDisplay).isNull()
         }
@@ -191,24 +192,162 @@
     @Test
     fun onDisplayDisconnected_unknownDisplay_doesNotSendNull() =
         testScope.runTest {
-            val pendingDisplay by latestPendingDisplayFlowValue()
-            displayListener.value.onDisplayConnected(1)
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
 
             assertThat(pendingDisplay).isNotNull()
 
-            displayListener.value.onDisplayDisconnected(2)
+            sendOnDisplayDisconnected(2)
 
             assertThat(pendingDisplay).isNotNull()
         }
 
     @Test
-    fun onDisplayConnected_multipleTimes_sendsOnlyTheLastOne() =
+    fun onDisplayConnected_multipleTimes_sendsOnlyTheMaximum() =
         testScope.runTest {
-            val pendingDisplay by latestPendingDisplayFlowValue()
-            displayListener.value.onDisplayConnected(1)
-            displayListener.value.onDisplayConnected(2)
+            val pendingDisplay by lastPendingDisplay()
 
-            assertThat(pendingDisplay).isEqualTo(2)
+            sendOnDisplayConnected(1)
+            sendOnDisplayConnected(2)
+
+            assertThat(pendingDisplay!!.id).isEqualTo(2)
+        }
+
+    @Test
+    fun onPendingDisplay_enable_displayEnabled() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.enable()
+
+            verify(displayManager).enableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_enableBySysui_disabledBySomeoneElse_pendingDisplayStillIgnored() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.enable()
+            // to mock the display being really enabled:
+            sendOnDisplayAdded(1)
+
+            // Simulate the display being disabled by someone else. Now, sysui will have it in the
+            // "pending displays" list again, but it should be ignored.
+            sendOnDisplayRemoved(1)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_ignoredBySysui_enabledDisabledBySomeoneElse_pendingDisplayStillIgnored() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.ignore()
+
+            // to mock the display being enabled and disabled by someone else:
+            sendOnDisplayAdded(1)
+            sendOnDisplayRemoved(1)
+
+            // Sysui already decided to ignore it, so the pending display should be null.
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_disable_displayDisabled() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.disable()
+
+            verify(displayManager).disableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_ignore_pendingDisplayNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
+
+            pendingDisplay!!.ignore()
+
+            assertThat(pendingDisplay).isNull()
+            verify(displayManager, never()).disableConnectedDisplay(eq(1))
+            verify(displayManager, never()).enableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_enabled_pendingDisplayNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            assertThat(pendingDisplay).isNotNull()
+
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_multipleConnected_oneEnabled_pendingDisplayNotNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            sendOnDisplayConnected(2)
+
+            assertThat(pendingDisplay).isNotNull()
+
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            assertThat(pendingDisplay).isNotNull()
+            assertThat(pendingDisplay!!.id).isEqualTo(2)
+
+            setDisplays(1, 2)
+            sendOnDisplayAdded(2)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun pendingDisplay_connectedDisconnectedAndReconnected_expectedPendingDisplayState() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            // Plug the cable
+            sendOnDisplayConnected(1)
+
+            // Enable it
+            assertThat(pendingDisplay).isNotNull()
+            pendingDisplay!!.enable()
+
+            // Enabled
+            verify(displayManager).enableConnectedDisplay(1)
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            // No more pending displays
+            assertThat(pendingDisplay).isNull()
+
+            // Let's disconnect the cable
+            setDisplays()
+            sendOnDisplayRemoved(1)
+            sendOnDisplayDisconnected(1)
+
+            assertThat(pendingDisplay).isNull()
+
+            // Let's reconnect it
+            sendOnDisplayConnected(1)
+
+            assertThat(pendingDisplay).isNotNull()
         }
 
     private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
@@ -216,6 +355,23 @@
     // Wrapper to capture the displayListener.
     private fun TestScope.latestDisplayFlowValue(): FlowValue<Set<Display>?> {
         val flowValue = collectLastValue(displayRepository.displays)
+        captureAddedRemovedListener()
+        return flowValue
+    }
+
+    private fun TestScope.lastPendingDisplay(): FlowValue<DisplayRepository.PendingDisplay?> {
+        val flowValue = collectLastValue(displayRepository.pendingDisplay)
+        captureAddedRemovedListener()
+        verify(displayManager)
+            .registerDisplayListener(
+                connectedDisplayListener.capture(),
+                eq(testHandler),
+                eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
+            )
+        return flowValue
+    }
+
+    private fun captureAddedRemovedListener() {
         verify(displayManager)
             .registerDisplayListener(
                 displayListener.capture(),
@@ -226,18 +382,20 @@
                         DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
                 )
             )
-        return flowValue
+    }
+    private fun sendOnDisplayAdded(id: Int) {
+        displayListener.value.onDisplayAdded(id)
+    }
+    private fun sendOnDisplayRemoved(id: Int) {
+        displayListener.value.onDisplayRemoved(id)
     }
 
-    private fun TestScope.latestPendingDisplayFlowValue(): FlowValue<Int?> {
-        val flowValue = collectLastValue(displayRepository.pendingDisplayId)
-        verify(displayManager)
-            .registerDisplayListener(
-                displayListener.capture(),
-                eq(testHandler),
-                eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
-            )
-        return flowValue
+    private fun sendOnDisplayDisconnected(id: Int) {
+        connectedDisplayListener.value.onDisplayDisconnected(id)
+    }
+
+    private fun sendOnDisplayConnected(id: Int) {
+        connectedDisplayListener.value.onDisplayConnected(id)
     }
 
     private fun setDisplays(displays: List<Display>) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index 50617a1..26ee094 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.display.domain.interactor
 
-import android.hardware.display.DisplayManager
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.Display
@@ -27,12 +26,11 @@
 import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.display.data.repository.createPendingDisplay
 import com.android.systemui.display.data.repository.display
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
@@ -41,7 +39,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito
 
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
@@ -49,20 +46,15 @@
 @SmallTest
 class ConnectedDisplayInteractorTest : SysuiTestCase() {
 
-    private val displayManager = mock<DisplayManager>()
     private val fakeDisplayRepository = FakeDisplayRepository()
     private val fakeKeyguardRepository = FakeKeyguardRepository()
     private val connectedDisplayStateProvider: ConnectedDisplayInteractor =
-        ConnectedDisplayInteractorImpl(
-            displayManager,
-            fakeKeyguardRepository,
-            fakeDisplayRepository
-        )
+        ConnectedDisplayInteractorImpl(fakeKeyguardRepository, fakeDisplayRepository)
     private val testScope = TestScope(UnconfinedTestDispatcher())
 
     @Before
     fun setup() {
-        fakeKeyguardRepository.setKeyguardUnlocked(true)
+        fakeKeyguardRepository.setKeyguardShowing(false)
     }
 
     @Test
@@ -148,7 +140,7 @@
     fun pendingDisplay_propagated() =
         testScope.runTest {
             val value by lastPendingDisplay()
-            val pendingDisplayId = 4
+            val pendingDisplayId = createPendingDisplay()
 
             fakeDisplayRepository.emit(pendingDisplayId)
 
@@ -156,51 +148,29 @@
         }
 
     @Test
-    fun onPendingDisplay_enable_displayEnabled() =
+    fun onPendingDisplay_keyguardShowing_returnsPendingDisplay() =
         testScope.runTest {
+            fakeKeyguardRepository.setKeyguardShowing(true)
             val pendingDisplay by lastPendingDisplay()
 
-            fakeDisplayRepository.emit(1)
-            pendingDisplay!!.enable()
-
-            Mockito.verify(displayManager).enableConnectedDisplay(eq(1))
-        }
-
-    @Test
-    fun onPendingDisplay_disable_displayDisabled() =
-        testScope.runTest {
-            val pendingDisplay by lastPendingDisplay()
-
-            fakeDisplayRepository.emit(1)
-            pendingDisplay!!.disable()
-
-            Mockito.verify(displayManager).disableConnectedDisplay(eq(1))
-        }
-
-    @Test
-    fun onPendingDisplay_keyguardUnlocked_returnsPendingDisplay() =
-        testScope.runTest {
-            fakeKeyguardRepository.setKeyguardUnlocked(false)
-            val pendingDisplay by lastPendingDisplay()
-
-            fakeDisplayRepository.emit(1)
+            fakeDisplayRepository.emit(createPendingDisplay())
             assertThat(pendingDisplay).isNull()
 
-            fakeKeyguardRepository.setKeyguardUnlocked(true)
+            fakeKeyguardRepository.setKeyguardShowing(false)
 
             assertThat(pendingDisplay).isNotNull()
         }
 
     @Test
-    fun onPendingDisplay_keyguardLocked_returnsNull() =
+    fun onPendingDisplay_keyguardShowing_returnsNull() =
         testScope.runTest {
-            fakeKeyguardRepository.setKeyguardUnlocked(true)
+            fakeKeyguardRepository.setKeyguardShowing(false)
             val pendingDisplay by lastPendingDisplay()
 
-            fakeDisplayRepository.emit(1)
+            fakeDisplayRepository.emit(createPendingDisplay())
             assertThat(pendingDisplay).isNotNull()
 
-            fakeKeyguardRepository.setKeyguardUnlocked(false)
+            fakeKeyguardRepository.setKeyguardShowing(true)
 
             assertThat(pendingDisplay).isNull()
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
index 7059647..46f7582 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
@@ -68,6 +68,28 @@
         verify(onStartMirroringCallback, never()).onClick(any())
     }
 
+    @Test
+    fun onCancel_afterEnablingMirroring_cancelCallbackNotCalled() {
+        dialog.show()
+        dialog.requireViewById<View>(R.id.enable_display).callOnClick()
+
+        dialog.cancel()
+
+        verify(onCancelCallback, never()).onClick(any())
+        verify(onStartMirroringCallback).onClick(any())
+    }
+
+    @Test
+    fun onDismiss_afterEnablingMirroring_cancelCallbackNotCalled() {
+        dialog.show()
+        dialog.requireViewById<View>(R.id.enable_display).callOnClick()
+
+        dialog.dismiss()
+
+        verify(onCancelCallback, never()).onClick(any())
+        verify(onStartMirroringCallback).onClick(any())
+    }
+
     @After
     fun teardown() {
         if (::dialog.isInitialized) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index 6f51d1b..2ac625d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -30,20 +30,24 @@
     }
 }
 
+/** Creates a mock [DisplayRepository.PendingDisplay]. */
+fun createPendingDisplay(id: Int = 0): DisplayRepository.PendingDisplay =
+    mock<DisplayRepository.PendingDisplay> { whenever(this.id).thenReturn(id) }
+
 /** Fake [DisplayRepository] implementation for testing. */
 class FakeDisplayRepository : DisplayRepository {
     private val flow = MutableSharedFlow<Set<Display>>()
-    private val pendingDisplayFlow = MutableSharedFlow<Int?>()
+    private val pendingDisplayFlow = MutableSharedFlow<DisplayRepository.PendingDisplay?>()
 
     /** Emits [value] as [displays] flow value. */
     suspend fun emit(value: Set<Display>) = flow.emit(value)
 
-    /** Emits [value] as [pendingDisplayId] flow value. */
-    suspend fun emit(value: Int?) = pendingDisplayFlow.emit(value)
+    /** Emits [value] as [pendingDisplay] flow value. */
+    suspend fun emit(value: DisplayRepository.PendingDisplay?) = pendingDisplayFlow.emit(value)
 
     override val displays: Flow<Set<Display>>
         get() = flow
 
-    override val pendingDisplayId: Flow<Int?>
+    override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>
         get() = pendingDisplayFlow
 }
diff --git a/services/companion/java/com/android/server/companion/virtual/Android.bp b/services/companion/java/com/android/server/companion/virtual/Android.bp
index 7a7d376..6526c78 100644
--- a/services/companion/java/com/android/server/companion/virtual/Android.bp
+++ b/services/companion/java/com/android/server/companion/virtual/Android.bp
@@ -1,9 +1,6 @@
 java_aconfig_library {
     name: "virtualdevice_flags_lib",
     aconfig_declarations: "virtualdevice_flags",
-    static_libs: [
-        "android.companion.virtual.flags-aconfig-java",
-    ],
 }
 
 aconfig_declarations {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3aa09b..cbac39a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -559,6 +559,7 @@
     boolean mWakeOnDpadKeyPress;
     boolean mWakeOnAssistKeyPress;
     boolean mWakeOnBackKeyPress;
+    boolean mSilenceRingerOnSleepKey;
     long mWakeUpToLastStateTimeout;
     int mSearchKeyBehavior;
     ComponentName mSearchKeyTargetActivity;
@@ -1423,6 +1424,15 @@
     }
 
     private void sleepRelease(long eventTime) {
+        if (mSilenceRingerOnSleepKey) {
+            TelecomManager telecomManager = getTelecommService();
+            if (telecomManager != null && telecomManager.isRinging()) {
+                telecomManager.silenceRinger();
+                Slog.i(TAG, "sleepRelease() silence ringer");
+                return;
+            }
+        }
+
         switch (mShortPressOnSleepBehavior) {
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
@@ -2347,6 +2357,8 @@
                 com.android.internal.R.string.config_primaryShortPressTargetActivity));
         mShortPressOnSleepBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shortPressOnSleepBehavior);
+        mSilenceRingerOnSleepKey = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_silenceRingerOnSleepKey);
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 90e67df..582536b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2929,7 +2929,7 @@
         reparent(newTaskFrag, position);
     }
 
-    private boolean isHomeIntent(Intent intent) {
+    static boolean isHomeIntent(Intent intent) {
         return ACTION_MAIN.equals(intent.getAction())
                 && (intent.hasCategory(CATEGORY_HOME)
                 || intent.hasCategory(CATEGORY_SECONDARY_HOME))
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1eb56f1..a5b1132 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -55,6 +55,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -77,7 +78,6 @@
 
     private final ActivityTaskManagerService mService;
     private final ActivityTaskSupervisor mSupervisor;
-    private final RootWindowContainer mRootWindowContainer;
     private final Context mServiceContext;
 
     // UserManager cannot be final as it's not ready when this class is instantiated during boot
@@ -110,17 +110,23 @@
     TaskFragment mInTaskFragment;
     ActivityOptions mActivityOptions;
 
+    /*
+     * Note that this is just a hint of what the launch display area will be as it is
+     * based only on the information at the early pre-interception stage of starting the
+     * intent. The real launch display area calculated later may be different from this one.
+     */
+    TaskDisplayArea mPresumableLaunchDisplayArea;
+
     ActivityStartInterceptor(
             ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
-        this(service, supervisor, service.mRootWindowContainer, service.mContext);
+        this(service, supervisor, service.mContext);
     }
 
     @VisibleForTesting
     ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
-            RootWindowContainer root, Context context) {
+            Context context) {
         mService = service;
         mSupervisor = supervisor;
-        mRootWindowContainer = root;
         mServiceContext = context;
     }
 
@@ -162,7 +168,7 @@
     /**
      * A helper function to obtain the targeted {@link TaskFragment} during
      * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
-     * ActivityOptions)} if any.
+     * ActivityOptions, TaskDisplayArea)} if any.
      */
     @Nullable
     private TaskFragment getLaunchTaskFragment() {
@@ -187,7 +193,7 @@
      */
     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
             Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
-            ActivityOptions activityOptions) {
+            ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) {
         mUserManager = UserManager.get(mServiceContext);
 
         mIntent = intent;
@@ -199,6 +205,7 @@
         mInTask = inTask;
         mInTaskFragment = inTaskFragment;
         mActivityOptions = activityOptions;
+        mPresumableLaunchDisplayArea = presumableLaunchDisplayArea;
 
         if (interceptQuietProfileIfNeeded()) {
             // If work profile is turned off, skip the work challenge since the profile can only
@@ -221,6 +228,11 @@
         if (interceptLockedManagedProfileIfNeeded()) {
             return true;
         }
+        if (interceptHomeIfNeeded()) {
+            // Replace primary home intents directed at displays that do not support primary home
+            // but support secondary home with the relevant secondary home activity.
+            return true;
+        }
 
         final SparseArray<ActivityInterceptorCallback> callbacks =
                 mService.getActivityInterceptorCallbacks();
@@ -470,6 +482,47 @@
         return true;
     }
 
+    private boolean interceptHomeIfNeeded() {
+        if (mPresumableLaunchDisplayArea == null || mService.mRootWindowContainer == null) {
+            return false;
+        }
+        if (!ActivityRecord.isHomeIntent(mIntent)) {
+            return false;
+        }
+        if (!mIntent.hasCategory(Intent.CATEGORY_HOME)) {
+            // Already a secondary home intent, leave it alone.
+            return false;
+        }
+        if (mService.mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(
+                mPresumableLaunchDisplayArea.getDisplayId())) {
+            // Primary home can be launched to the display area.
+            return false;
+        }
+        if (!mService.mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(
+                mPresumableLaunchDisplayArea)) {
+            // Secondary home cannot be launched on the display area.
+            return false;
+        }
+
+        // At this point we have a primary home intent for a display that does not support primary
+        // home activity but it supports secondary home one. So replace it with secondary home.
+        Pair<ActivityInfo, Intent> info = mService.mRootWindowContainer
+                .resolveSecondaryHomeActivity(mUserId, mPresumableLaunchDisplayArea);
+        mIntent = info.second;
+        // The new task flag is needed because the home activity should already be in the root task
+        // and should not be moved to the caller's task. Also, activities cannot change their type,
+        // e.g. a standard activity cannot become a home activity.
+        mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0,
+                mRealCallingUid, mRealCallingPid);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ null);
+        return true;
+    }
+
     private boolean isPackageSuspended() {
         return mAInfo != null && mAInfo.applicationInfo != null
                 && (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) != 0;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1bc78d6..458d1e8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1154,10 +1154,12 @@
             }
         }
 
+        final TaskDisplayArea suggestedLaunchDisplayArea =
+                computeSuggestedLaunchDisplayArea(inTask, sourceRecord, checkedOptions);
         mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
                 callingFeatureId);
         if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
-                callingPid, callingUid, checkedOptions)) {
+                callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) {
             // activity start was intercepted, e.g. because the target user is currently in quiet
             // mode (turn off work) or the target application is suspended
             intent = mInterceptor.mIntent;
@@ -1890,6 +1892,15 @@
         mPreferredWindowingMode = mLaunchParams.mWindowingMode;
     }
 
+    private TaskDisplayArea computeSuggestedLaunchDisplayArea(
+            Task task, ActivityRecord source, ActivityOptions options) {
+        mSupervisor.getLaunchParamsController().calculate(task, /*layout=*/null,
+                /*activity=*/ null, source, options, mRequest, PHASE_DISPLAY, mLaunchParams);
+        return mLaunchParams.hasPreferredTaskDisplayArea()
+                ? mLaunchParams.mPreferredTaskDisplayArea
+                : mRootWindowContainer.getDefaultTaskDisplayArea();
+    }
+
     @VisibleForTesting
     int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
         if (r.packageName == null) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 57f8268..d56acaa 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1608,6 +1608,19 @@
     }
 
     /**
+     * Check if the display is valid for primary home activity.
+     *
+     * @param displayId The target display ID
+     * @return {@code true} if allowed to launch, {@code false} otherwise.
+     */
+    boolean shouldPlacePrimaryHomeOnDisplay(int displayId) {
+        // No restrictions to default display, vr 2d display or main display for visible users.
+        return displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
+                && (displayId == mService.mVr2dDisplayId
+                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)));
+    }
+
+    /**
      * Check if the display area is valid for secondary home activity.
      *
      * @param taskDisplayArea The target display area.
@@ -1680,10 +1693,7 @@
 
         final int displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId()
                 : INVALID_DISPLAY;
-        if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
-                && (displayId == mService.mVr2dDisplayId
-                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)))) {
-            // No restrictions to default display, vr 2d display or main display for visible users.
+        if (shouldPlacePrimaryHomeOnDisplay(displayId)) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 387a876..21a4fe8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2815,7 +2815,7 @@
         final WindowManager.LayoutParams attrs = win.mAttrs;
         visibleFrame.set(win.getFrame());
         visibleFrame.inset(win.getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                visibleFrame, attrs.type, win.getWindowingMode(), attrs.softInputMode,
+                visibleFrame, attrs.type, win.getActivityType(), attrs.softInputMode,
                 attrs.flags));
         out.union(visibleFrame);
     }
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index ad46770..fa620db 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -118,12 +118,14 @@
             root = activity;
         }
 
-        if (root == null) {
+        if (root == null && phase != PHASE_DISPLAY) {
             // There is a case that can lead us here. The caller is moving the top activity that is
             // in a task that has multiple activities to PIP mode. For that the caller is creating a
             // new task to host the activity so that we only move the top activity to PIP mode and
             // keep other activities in the previous task. There is no point to apply the launch
             // logic in this case.
+            // However, for PHASE_DISPLAY the root may be null, but we still want to get a hint of
+            // what the suggested launch display area would be.
             return RESULT_SKIP;
         }
 
@@ -395,8 +397,9 @@
     }
 
     private TaskDisplayArea getPreferredLaunchTaskDisplayArea(@Nullable Task task,
-            @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams,
-            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+            @Nullable ActivityOptions options, @Nullable ActivityRecord source,
+            @Nullable LaunchParams currentParams, @Nullable ActivityRecord activityRecord,
+            @Nullable Request request) {
         TaskDisplayArea taskDisplayArea = null;
 
         final WindowContainerToken optionLaunchTaskDisplayAreaToken = options != null
@@ -438,8 +441,7 @@
 
         // If the source activity is a no-display activity, pass on the launch display area token
         // from source activity as currently preferred.
-        if (taskDisplayArea == null && source != null
-                && source.noDisplay) {
+        if (taskDisplayArea == null && source != null && source.noDisplay) {
             taskDisplayArea = source.mHandoverTaskDisplayArea;
             if (taskDisplayArea != null) {
                 if (DEBUG) appendLog("display-area-from-no-display-source=" + taskDisplayArea);
@@ -478,21 +480,24 @@
             }
         }
 
-        if (taskDisplayArea == null) {
+        if (taskDisplayArea == null && currentParams != null) {
             taskDisplayArea = currentParams.mPreferredTaskDisplayArea;
+            if (DEBUG) appendLog("display-area-from-current-params=" + taskDisplayArea);
         }
 
         // Re-route to default display if the device didn't declare support for multi-display
         if (taskDisplayArea != null && !mSupervisor.mService.mSupportsMultiDisplay
                 && taskDisplayArea.getDisplayId() != DEFAULT_DISPLAY) {
             taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+            if (DEBUG) appendLog("display-area-from-no-multidisplay=" + taskDisplayArea);
         }
 
         // Re-route to default display if the home activity doesn't support multi-display
-        if (taskDisplayArea != null && activityRecord.isActivityTypeHome()
+        if (taskDisplayArea != null && activityRecord != null && activityRecord.isActivityTypeHome()
                 && !mSupervisor.mRootWindowContainer.canStartHomeOnDisplayArea(activityRecord.info,
                         taskDisplayArea, false /* allowInstrumenting */)) {
             taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+            if (DEBUG) appendLog("display-area-from-home=" + taskDisplayArea);
         }
 
         return (taskDisplayArea != null)
@@ -516,34 +521,56 @@
      * @return {@link TaskDisplayArea} to house the task
      */
     private TaskDisplayArea getFallbackDisplayAreaForActivity(
-            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+            @Nullable ActivityRecord activityRecord, @Nullable Request request) {
+        if (activityRecord != null) {
+            WindowProcessController controllerFromLaunchingRecord =
+                    mSupervisor.mService.getProcessController(
+                            activityRecord.launchedFromPid, activityRecord.launchedFromUid);
+            if (controllerFromLaunchingRecord != null) {
+                final TaskDisplayArea taskDisplayAreaForLaunchingRecord =
+                        controllerFromLaunchingRecord.getTopActivityDisplayArea();
+                if (taskDisplayAreaForLaunchingRecord != null) {
+                    if (DEBUG) {
+                        appendLog("display-area-for-launching-record="
+                                + taskDisplayAreaForLaunchingRecord);
+                    }
+                    return taskDisplayAreaForLaunchingRecord;
+                }
+            }
 
-        WindowProcessController controllerFromLaunchingRecord = mSupervisor.mService
-                .getProcessController(activityRecord.launchedFromPid,
-                        activityRecord.launchedFromUid);
-        final TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
-                ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
-        if (displayAreaForLaunchingRecord != null) {
-            return displayAreaForLaunchingRecord;
+            WindowProcessController controllerFromProcess =
+                    mSupervisor.mService.getProcessController(
+                            activityRecord.getProcessName(), activityRecord.getUid());
+            if (controllerFromProcess != null) {
+                final TaskDisplayArea displayAreaForRecord =
+                        controllerFromProcess.getTopActivityDisplayArea();
+                if (displayAreaForRecord != null) {
+                    if (DEBUG) appendLog("display-area-for-record=" + displayAreaForRecord);
+                    return displayAreaForRecord;
+                }
+            }
         }
 
-        WindowProcessController controllerFromProcess = mSupervisor.mService.getProcessController(
-                activityRecord.getProcessName(), activityRecord.getUid());
-        final TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
-                : controllerFromProcess.getTopActivityDisplayArea();
-        if (displayAreaForRecord != null) {
-            return displayAreaForRecord;
+        if (request != null) {
+            WindowProcessController controllerFromRequest =
+                    mSupervisor.mService.getProcessController(
+                            request.realCallingPid, request.realCallingUid);
+            if (controllerFromRequest != null) {
+                final TaskDisplayArea displayAreaFromSourceProcess =
+                            controllerFromRequest.getTopActivityDisplayArea();
+                if (displayAreaFromSourceProcess != null) {
+                    if (DEBUG) {
+                        appendLog("display-area-source-process=" + displayAreaFromSourceProcess);
+                    }
+                    return displayAreaFromSourceProcess;
+                }
+            }
         }
 
-        WindowProcessController controllerFromRequest = request == null ? null : mSupervisor
-                .mService.getProcessController(request.realCallingPid, request.realCallingUid);
-        final TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
-                : controllerFromRequest.getTopActivityDisplayArea();
-        if (displayAreaFromSourceProcess != null) {
-            return displayAreaFromSourceProcess;
-        }
-
-        return mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+        final TaskDisplayArea defaultTaskDisplayArea =
+                mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+        if (DEBUG) appendLog("display-area-from-default-fallback=" + defaultTaskDisplayArea);
+        return defaultTaskDisplayArea;
     }
 
     private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a172d99..9c04e0a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1759,7 +1759,7 @@
 
         bounds.set(mWindowFrames.mFrame);
         bounds.inset(getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                bounds, mAttrs.type, getWindowingMode(), mAttrs.softInputMode, mAttrs.flags));
+                bounds, mAttrs.type, getActivityType(), mAttrs.softInputMode, mAttrs.flags));
         if (intersectWithRootTaskBounds) {
             bounds.intersect(mTmpRect);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index bcb0c6b..0989db4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -59,6 +59,7 @@
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 import android.testing.DexmakerShareClassLoaderRule;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -128,6 +129,8 @@
     private ActivityManagerInternal mAmInternal;
     @Mock
     private LockTaskController mLockTaskController;
+    @Mock
+    private TaskDisplayArea mTaskDisplayArea;
 
     private ActivityStartInterceptor mInterceptor;
     private ActivityInfo mAInfo = new ActivityInfo();
@@ -139,8 +142,8 @@
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
         mService.mAmInternal = mAmInternal;
-        mInterceptor = new ActivityStartInterceptor(
-                mService, mSupervisor, mRootWindowContainer, mContext);
+        mService.mRootWindowContainer = mRootWindowContainer;
+        mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext);
         mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID,
                 TEST_START_FLAGS, TEST_CALLING_PACKAGE, null);
 
@@ -201,7 +204,7 @@
                 .thenReturn(PLATFORM_PACKAGE_NAME);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the admin support intent
         assertEquals(ADMIN_SUPPORT_INTENT, mInterceptor.mIntent);
@@ -212,7 +215,7 @@
         final String suspendingPackage = "com.test.suspending.package";
         final SuspendDialogInfo dialogInfo = suspendPackage(suspendingPackage);
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // Check intent parameters
         assertEquals(dialogInfo,
@@ -243,7 +246,7 @@
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
                 .thenReturn(false);
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME)
                 .filterEquals(mInterceptor.mIntent));
@@ -257,7 +260,8 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
 
         // THEN calling intercept returns false because package also has to be suspended.
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null));
+        assertFalse(
+                mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null, null));
     }
 
     @Test
@@ -268,7 +272,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -284,7 +288,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -300,7 +304,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -313,7 +317,7 @@
         when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is the confirm credentials intent
         assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
@@ -329,7 +333,7 @@
         mAInfo.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is original intent
         assertSame(originalIntent, mInterceptor.mIntent);
@@ -345,7 +349,7 @@
         mAInfo.directBootAware = false;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is the confirm credentials intent
         assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
@@ -362,7 +366,7 @@
         mAInfo.directBootAware = true;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is original intent
         assertSame(originalIntent, mInterceptor.mIntent);
@@ -375,7 +379,7 @@
                 .thenReturn("This app is bad");
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the harmful app warning intent
         assertEquals(HarmfulAppWarningActivity.class.getName(),
@@ -383,11 +387,40 @@
     }
 
     @Test
+    public void testHomeIntentInterception() {
+        // GIVEN a primary home intent and a display area that doesn't support it but supports
+        // secondary home activities
+        Intent originalIntent = new Intent(Intent.ACTION_MAIN);
+        originalIntent.addCategory(Intent.CATEGORY_HOME);
+
+        Intent expectedIntent = new Intent(Intent.ACTION_MAIN);
+        expectedIntent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
+        expectedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final int secondaryDisplayId = 7;
+        when(mTaskDisplayArea.getDisplayId()).thenReturn(secondaryDisplayId);
+        when(mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(eq(secondaryDisplayId)))
+                .thenReturn(false);
+        when(mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(eq(mTaskDisplayArea)))
+                .thenReturn(true);
+        when(mRootWindowContainer.resolveSecondaryHomeActivity(
+                eq(TEST_USER_ID), eq(mTaskDisplayArea)))
+                .thenReturn(Pair.create(null, expectedIntent));
+
+        // THEN calling intercept returns true
+        assertTrue(mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0,
+                null, mTaskDisplayArea));
+
+        // THEN the returned intent is the secondary home intent
+        assertSame(expectedIntent, mInterceptor.mIntent);
+    }
+
+    @Test
     public void testNoInterception() {
         // GIVEN that none of the interception conditions are met
 
         // THEN calling intercept returns false
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
     }
 
     public void addMockInterceptorCallback(
@@ -420,7 +453,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3));
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
     }
@@ -429,7 +462,7 @@
     public void testInterceptionCallback_singleCallbackReturnsNull() {
         addMockInterceptorCallback(null, null);
 
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
     }
 
     @Test
@@ -437,7 +470,7 @@
         addMockInterceptorCallback(null, null);
         addMockInterceptorCallback(new Intent("android.test.second"), null);
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.second", mInterceptor.mIntent.getAction());
     }
 
@@ -447,7 +480,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3), true);
         ActivityInfo aInfo = mAInfo;
-        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
         assertEquals(aInfo, mInterceptor.mAInfo); // mAInfo should not be resolved
@@ -459,7 +492,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3));
         ActivityInfo aInfo = mAInfo;
-        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
         assertNotEquals(aInfo, mInterceptor.mAInfo); // mAInfo should be resolved after intercept
@@ -488,7 +521,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setAction(ACTION_START_SANDBOXED_ACTIVITY);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -505,7 +538,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setPackage(sandboxPackageNameMock);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -522,7 +555,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setComponent(new ComponentName(sandboxPackageNameMock, ""));
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -539,23 +572,23 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         // Intent: null
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Action: null, Package: null, ComponentName: null
         Intent intent = new Intent();
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong Action
         intent = new Intent().setAction(Intent.ACTION_VIEW);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong Package
         intent = new Intent().setPackage("Random");
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong ComponentName's package
         intent = new Intent().setComponent(new ComponentName("Random", ""));
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, never()).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0bb75d8..ac8200a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9456,6 +9456,19 @@
             "carrier_supported_satellite_services_per_provider_bundle";
 
     /**
+     * This config enables modem to scan satellite PLMNs specified as per
+     * {@link #KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE} and attach to same
+     * in case cellular networks are not enabled. This will need specific agreement between
+     * satellite provider and the carrier before enabling this flag.
+     *
+     * The default value is false.
+     *
+     * @hide
+     */
+    public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL =
+            "satellite_attach_supported_bool";
+
+    /**
      * Indicating whether DUN APN should be disabled when the device is roaming. In that case,
      * the default APN (i.e. internet) will be used for tethering.
      *
@@ -10465,6 +10478,7 @@
         sDefaults.putPersistableBundle(
                 KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 PersistableBundle.EMPTY);
+        sDefaults.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 75b5f55..5f6c14a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -44,10 +44,14 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc.
@@ -79,6 +83,23 @@
     @Nullable private final Context mContext;
 
     /**
+     * Create a new SatelliteManager object pinned to the given subscription ID.
+     * This is needed only to handle carrier specific satellite features.
+     * For eg: requestSatelliteAttachEnabledForCarrier and
+     *         requestIsSatelliteAttachEnabledForCarrier
+     *
+     * @return a SatelliteManager that uses the given subId for all satellite activities.
+     * @throws IllegalArgumentException if the subscription is invalid.
+     * @hide
+     */
+    public SatelliteManager createForSubscriptionId(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+        return new SatelliteManager(mContext, subId);
+    }
+
+    /**
      * Create an instance of the SatelliteManager.
      *
      * @param context The context the SatelliteManager belongs to.
@@ -791,6 +812,27 @@
     public @interface DatagramType {}
 
     /**
+     * Satellite communication restricted by user.
+     * @hide
+     */
+    public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0;
+
+    /**
+     * Satellite communication restricted by geolocation. This can be
+     * triggered based upon geofence input provided by carrier to enable or disable satellite.
+     * @hide
+     */
+    public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1;
+
+    /** @hide */
+    @IntDef(prefix = "SATELLITE_COMMUNICATION_RESTRICTION_REASON_", value = {
+            SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER,
+            SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SatelliteCommunicationRestrictionReason {}
+
+    /**
      * Start receiving satellite transmission updates.
      * This can be called by the pointing UI when the user starts pointing to the satellite.
      * Modem should continue to report the pointing input as the device or satellite moves.
@@ -1559,6 +1601,182 @@
         }
     }
 
+    /**
+     * User request to enable or disable carrier supported satellite plmn scan and attach by modem.
+     * <p>
+     * This API should be called by only settings app to pass down the user input for
+     * enabling/disabling satellite. This user input will be persisted across device reboots.
+     * <p>
+     * Satellite will be enabled only when the following conditions are met:
+     * <ul>
+     * <li>Users want to enable it.</li>
+     * <li>There is no satellite communication restriction, which is added by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, Executor, Consumer)}</li>
+     * <li>The carrier config {@link
+     * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
+     * {@code true}.</li>
+     * </ul>
+     *
+     * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void requestSatelliteAttachEnabledForCarrier(boolean enableSatellite,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(resultListener);
+
+        if (enableSatellite) {
+            removeSatelliteAttachRestrictionForCarrier(
+                    SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
+        } else {
+            addSatelliteAttachRestrictionForCarrier(
+                    SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
+        }
+    }
+
+    /**
+     * Request to get whether the carrier supported satellite plmn scan and attach by modem is
+     * enabled by user.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback object to which the result will be delivered.
+     *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+     *                 will return a {@code boolean} with value {@code true} if the satellite
+     *                 is enabled and {@code false} otherwise.
+     *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void requestIsSatelliteAttachEnabledForCarrier(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier();
+        executor.execute(() -> callback.onResult(
+                !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
+    }
+
+    /**
+     * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
+     * by modem.
+     *
+     * @param reason Reason for disallowing satellite communication.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void addSatelliteAttachRestrictionForCarrier(
+            @SatelliteCommunicationRestrictionReason int reason,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> resultListener.accept(result)));
+                    }
+                };
+                telephony.addSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("addSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
+     * by modem.
+     *
+     * @param reason Reason for disallowing satellite communication.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void removeSatelliteAttachRestrictionForCarrier(
+            @SatelliteCommunicationRestrictionReason int reason,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> resultListener.accept(result)));
+                    }
+                };
+                telephony.removeSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("removeSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get reasons for disallowing satellite attach, as requested by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, Executor, Consumer)}
+     *
+     * @return Set of reasons for disallowing satellite communication.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    @SatelliteCommunicationRestrictionReason
+    public @NonNull Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                int[] receivedArray =
+                        telephony.getSatelliteAttachRestrictionReasonsForCarrier(mSubId);
+                if (receivedArray.length == 0) {
+                    logd("received set is empty, create empty set");
+                    return new HashSet<>();
+                } else {
+                    return Arrays.stream(receivedArray).boxed().collect(Collectors.toSet());
+                }
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("getSatelliteAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
+            ex.rethrowFromSystemServer();
+        }
+        return null;
+    }
+
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
                 .getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index ea4e2e2..02661de 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -382,4 +382,64 @@
      */
     void requestTimeForNextSatelliteVisibility(in IIntegerConsumer resultCallback,
             in IIntegerConsumer callback);
+
+    /**
+     * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
+     * MCC/MNC broadcast by the non-terrestrial networks may not be included in OPLMNwACT file on
+     * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
+     * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
+     * satellite LTE service.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *
+     * Valid error codes returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_ARGUMENTS
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:NO_RESOURCES
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void setSatellitePlmn(int simSlot, in List<String> plmnList,
+            in IIntegerConsumer resultCallback);
+
+    /**
+     * Enable or disable satellite in the cellular modem associated with a carrier.
+     * Refer setSatellitePlmn for the details of satellite PLMN scanning process.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param serial Serial number of request.
+     * @param enable {@code true} to enable satellite, {@code false} to disable satellite.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void setSatelliteEnabledForCarrier(int simSlot, boolean satelliteEnabled,
+         in IIntegerConsumer callback);
+
+    /**
+     * Check whether satellite is enabled in the cellular modem associated with a carrier.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param serial Serial number of request.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void requestIsSatelliteEnabledForCarrier(int simSlot, in IIntegerConsumer resultCallback,
+            in IBooleanConsumer callback);
 }
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index 17d026c..6451daf 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -25,6 +25,7 @@
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.util.TelephonyUtils;
 
+import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
@@ -212,6 +213,34 @@
                     "requestTimeForNextSatelliteVisibility");
         }
 
+        @Override
+        public void setSatellitePlmn(int simSlot, List<String> plmnList,
+                IIntegerConsumer errorCallback)
+                throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .setSatellitePlmn(simSlot, plmnList, errorCallback),
+                    "setSatellitePlmn");
+        }
+
+        @Override
+        public void setSatelliteEnabledForCarrier(int simSlot, boolean enableSatellite,
+                IIntegerConsumer errorCallback) throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .setSatelliteEnabledForCarrier(simSlot, enableSatellite, errorCallback),
+                    "setSatelliteEnabledForCarrier");
+        }
+
+        @Override
+        public void requestIsSatelliteEnabledForCarrier(int simSlot, IIntegerConsumer errorCallback,
+                IBooleanConsumer callback) throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .requestIsSatelliteEnabledForCarrier(simSlot, errorCallback, callback),
+                    "requestIsSatelliteEnabledForCarrier");
+        }
+
         // Call the methods with a clean calling identity on the executor and wait indefinitely for
         // the future to return.
         private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
@@ -618,4 +647,75 @@
             @NonNull IIntegerConsumer callback) {
         // stub implementation
     }
+
+
+    /**
+     * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
+     * MCC/MNC broadcast by the non-terrestrial networks may not be included in OPLMNwACT file on
+     * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
+     * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
+     * satellite LTE service.
+     * This method must only take effect if {@link #setSatelliteEnabledForCarrier} is {@code true},
+     * and return an error otherwise.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     *
+     * Valid error codes returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_ARGUMENTS
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:NO_RESOURCES
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void setSatellitePlmn(@NonNull int simLogicalSlotIndex, @NonNull List<String> plmnList,
+            @NonNull IIntegerConsumer errorCallback) {
+        // stub implementation
+    }
+
+    /**
+     * Request to enable or disable carrier supported satellite plmn scan and attach by modem.
+     * Refer {@link #setSatellitePlmn} for the details of satellite PLMN scanning process.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param satelliteEnabled {@code true} to enable satellite, {@code false} to disable satellite.
+     * @param callback {@code true} to enable satellite, {@code false} to disable satellite.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void setSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
+            @NonNull boolean satelliteEnabled, @NonNull IIntegerConsumer callback) {
+        // stub implementation
+    }
+
+    /**
+     * Request to get whether the satellite is enabled in the cellular modem associated with a
+     * carrier.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param callback {@code true} to satellite enabled, {@code false} to satellite disabled.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void requestIsSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
+            @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+        // stub implementation
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 06071fe..3aa5a5a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3033,4 +3033,42 @@
      @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
                  + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
      List<String> getShaIdFromAllowList(String pkgName, int carrierId);
+
+    /**
+     * Add a restriction reason for disallowing satellite communication.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param reason Reason for disallowing satellite communication for carrier.
+     * @param callback Listener for the {@link SatelliteManager.SatelliteError} result of the
+     * operation.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void addSatelliteAttachRestrictionForCarrier(int subId, int reason,
+            in IIntegerConsumer callback);
+
+    /**
+     * Remove a restriction reason for disallowing satellite communication.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param reason Reason for disallowing satellite communication.
+     * @param callback Listener for the {@link SatelliteManager.SatelliteError} result of the
+     * operation.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void removeSatelliteAttachRestrictionForCarrier(int subId, int reason,
+            in IIntegerConsumer callback);
+
+    /**
+     * Get reasons for disallowing satellite communication, as requested by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, int)}.
+     *
+     * @param subId The subId of the subscription to request for.
+     *
+     * @return Set of reasons for disallowing satellite communication.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    int[] getSatelliteAttachRestrictionReasonsForCarrier(int subId);
 }
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index a2ae56e..2ccc0fa 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -95,7 +95,6 @@
         "flickertestapplib",
         "flickerlib",
         "flickerlib-helpers",
-        "flickerlib-trace_processor_shell",
         "platform-test-annotations",
         "wm-flicker-common-app-helpers",
         "wm-shell-flicker-utils",
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/manifests/AndroidManifest.xml
index 6bc7cbe..1a34d9e 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/manifests/AndroidManifest.xml
@@ -44,12 +44,8 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <!-- ActivityOptions.makeCustomTaskAnimation() -->
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
-    <!-- Allow the test to connect to perfetto trace processor -->
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
-    <application android:requestLegacyExternalStorage="true"
-                 android:networkSecurityConfig="@xml/network_security_config"
-                 android:largeHeap="true">
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <application android:requestLegacyExternalStorage="true" android:largeHeap="true">
         <uses-library android:name="android.test.runner"/>
         <uses-library android:name="androidx.window.extensions" android:required="false"/>
 
diff --git a/tests/FlickerTests/res/xml/network_security_config.xml b/tests/FlickerTests/res/xml/network_security_config.xml
deleted file mode 100644
index 4bd9ca0..0000000
--- a/tests/FlickerTests/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">localhost</domain>
-    </domain-config>
-</network-security-config>
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index 38313f8..dc75f00 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -23,10 +23,7 @@
 
 android_test {
     name: "SurfaceViewBufferTests",
-    srcs: [
-        "**/*.java",
-        "**/*.kt",
-    ],
+    srcs: ["**/*.java","**/*.kt"],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
@@ -44,7 +41,6 @@
         "kotlin-stdlib",
         "kotlinx-coroutines-android",
         "flickerlib",
-        "flickerlib-trace_processor_shell",
         "truth-prebuilt",
         "cts-wm-util",
         "CtsSurfaceValidatorLib",
@@ -64,7 +60,7 @@
         "libandroid",
     ],
     include_dirs: [
-        "system/core/include",
+        "system/core/include"
     ],
     stl: "libc++_static",
     cflags: [
diff --git a/tests/SurfaceViewBufferTests/AndroidManifest.xml b/tests/SurfaceViewBufferTests/AndroidManifest.xml
index 798c67a..78415e8 100644
--- a/tests/SurfaceViewBufferTests/AndroidManifest.xml
+++ b/tests/SurfaceViewBufferTests/AndroidManifest.xml
@@ -29,12 +29,9 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <!-- Save failed test bitmap images !-->
     <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/>
-    <!-- Allow the test to connect to perfetto trace processor -->
-    <uses-permission android:name="android.permission.INTERNET"/>
 
     <application android:allowBackup="false"
-         android:supportsRtl="true"
-         android:networkSecurityConfig="@xml/network_security_config">
+         android:supportsRtl="true">
         <activity android:name=".MainActivity"
                   android:taskAffinity="com.android.test.MainActivity"
                   android:theme="@style/AppTheme"
diff --git a/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml b/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml
deleted file mode 100644
index 4bd9ca0..0000000
--- a/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">localhost</domain>
-    </domain-config>
-</network-security-config>
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index b03b733..a38019d 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -21,9 +21,11 @@
 import android.graphics.Rect
 import android.util.Log
 import androidx.test.ext.junit.rules.ActivityScenarioRule
+import android.tools.common.flicker.subject.layers.LayerSubject
 import android.tools.common.traces.surfaceflinger.LayersTrace
+import android.tools.device.traces.io.ResultWriter
+import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
 import android.tools.device.traces.monitors.withSFTracing
-import android.tools.device.traces.monitors.PerfettoTraceMonitor
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
@@ -31,7 +33,6 @@
 import java.io.FileOutputStream
 import java.io.IOException
 import java.util.concurrent.CountDownLatch
-import perfetto.protos.PerfettoConfig.SurfaceFlingerLayersConfig
 
 open class SurfaceTracingTestBase(useBlastAdapter: Boolean) :
         SurfaceViewBufferTestBase(useBlastAdapter) {
@@ -42,7 +43,7 @@
     @Before
     override fun setup() {
         super.setup()
-        PerfettoTraceMonitor.stopAllSessions()
+        stopLayerTrace()
         addSurfaceView()
     }
 
@@ -82,6 +83,10 @@
         instrumentation.waitForIdleSync()
     }
 
+    private fun stopLayerTrace() {
+        LayersTraceMonitor().stop(ResultWriter())
+    }
+
     fun checkPixels(bounds: Rect, @ColorInt color: Int) {
         val screenshot = instrumentation.getUiAutomation().takeScreenshot()
         val pixels = IntArray(screenshot.width * screenshot.height)
@@ -101,19 +106,14 @@
                         Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e)
                     }
                 }
-                Assert.assertEquals(
-                    "Checking $bounds found mismatch $i,$j",
-                    Color.valueOf(color),
-                    Color.valueOf(actualColor)
-                )
+                Assert.assertEquals("Checking $bounds found mismatch $i,$j",
+                        Color.valueOf(color), Color.valueOf(actualColor))
             }
         }
     }
 
     private companion object {
-        private val TRACE_FLAGS = listOf(
-            SurfaceFlingerLayersConfig.TraceFlag.TRACE_FLAG_BUFFERS,
-            SurfaceFlingerLayersConfig.TraceFlag.TRACE_FLAG_VIRTUAL_DISPLAYS,
-        )
+        private const val TRACE_FLAGS =
+                (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
     }
 }
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index bf12f42..9b72d35 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -25,10 +25,7 @@
 
 android_test {
     name: "TaskOrganizerTest",
-    srcs: [
-        "**/*.java",
-        "**/*.kt",
-    ],
+    srcs: ["**/*.java","**/*.kt"],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
@@ -42,7 +39,6 @@
         "kotlin-stdlib",
         "kotlinx-coroutines-android",
         "flickerlib",
-        "flickerlib-trace_processor_shell",
         "truth-prebuilt",
     ],
-}
+}
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index cbeb246..1f1bd3e 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -16,11 +16,9 @@
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
-    <!-- Allow the test to connect to perfetto trace processor -->
-    <uses-permission android:name="android.permission.INTERNET"/>
     <!-- Enable / Disable tracing !-->
     <uses-permission android:name="android.permission.DUMP" />
-    <application android:networkSecurityConfig="@xml/network_security_config">
+    <application>
       <activity android:name="TaskOrganizerMultiWindowTest"
            android:label="TaskOrganizer MW Test"
            android:exported="true"
diff --git a/tests/TaskOrganizerTest/res/xml/network_security_config.xml b/tests/TaskOrganizerTest/res/xml/network_security_config.xml
deleted file mode 100644
index e450a99..0000000
--- a/tests/TaskOrganizerTest/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-~ Copyright (C) 2023 The Android Open Source Project
-~
-~ Licensed under the Apache License, Version 2.0 (the "License");
-~ you may not use this file except in compliance with the License.
-~ You may obtain a copy of the License at
-~
-~      http://www.apache.org/licenses/LICENSE-2.0
-~
-~ Unless required by applicable law or agreed to in writing, software
-~ distributed under the License is distributed on an "AS IS" BASIS,
-~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-~ See the License for the specific language governing permissions and
-~ limitations under the License.
--->
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">localhost</domain>
-    </domain-config>
-</network-security-config>
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
index 2c7905d..6f4f7b1 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -22,6 +22,8 @@
 import androidx.test.runner.AndroidJUnit4
 import android.tools.common.datatypes.Size
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.device.traces.io.ResultWriter
+import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
 import android.tools.device.traces.monitors.withSFTracing
 import org.junit.After
 import org.junit.Before
@@ -39,13 +41,16 @@
     @get:Rule
     var scenarioRule: ActivityScenarioRule<TaskOrganizerMultiWindowTest> =
             ActivityScenarioRule<TaskOrganizerMultiWindowTest>(
-                    TaskOrganizerMultiWindowTest::class.java
-            )
+                    TaskOrganizerMultiWindowTest::class.java)
 
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
 
     @Before
     fun setup() {
+        val monitor = LayersTraceMonitor()
+        if (monitor.isEnabled) {
+            monitor.stop(ResultWriter())
+        }
         val firstTaskBounds = Rect(0, 0, 1080, 1000)
         val secondTaskBounds = Rect(0, 1000, 1080, 2000)
 
@@ -66,7 +71,7 @@
         val firstBounds = Rect(0, 0, 1080, 800)
         val secondBounds = Rect(0, 1000, 1080, 1800)
 
-        val trace = withSFTracing() {
+        val trace = withSFTracing(TRACE_FLAGS) {
             lateinit var resizeReadyLatch: CountDownLatch
             scenarioRule.getScenario().onActivity {
                 resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
@@ -101,6 +106,7 @@
     }
 
     companion object {
+        private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL
         private const val FIRST_ACTIVITY = "Activity1"
         private const val SECOND_ACTIVITY = "Activity2"
     }