Snap for 10453563 from 0a89c53ee1b86b387da37a227153a297af131731 to mainline-tzdata5-release

Change-Id: Iae2e2571b0a0c51a216a598f4101377cf889f884
diff --git a/builtInServices/Android.bp b/builtInServices/Android.bp
index c92a17c..e4f8a92 100644
--- a/builtInServices/Android.bp
+++ b/builtInServices/Android.bp
@@ -30,7 +30,6 @@
        "--include-annotations --pass-through-annotation android.annotation.RequiresApi"
     ],
 
-    min_sdk_version: "33",
     apex_available: [
         "//apex_available:platform",
         "com.android.car.framework"
diff --git a/builtInServices/api/module-lib-current.txt b/builtInServices/api/module-lib-current.txt
index b172240..ed6de32 100644
--- a/builtInServices/api/module-lib-current.txt
+++ b/builtInServices/api/module-lib-current.txt
@@ -74,6 +74,11 @@
     method public boolean supportsMultiDisplay();
   }
 
+  public interface CarActivityInterceptorInterface {
+    method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public int getMainDisplayAssignedToUser(int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public int getUserAssignedToDisplay(int);
+  }
+
   public interface CarActivityInterceptorUpdatable {
     method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @Nullable public com.android.server.wm.ActivityInterceptResultWrapper onInterceptActivityLaunch(com.android.server.wm.ActivityInterceptorInfoWrapper);
   }
@@ -116,6 +121,7 @@
   }
 
   public final class TaskWrapper {
+    method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public static com.android.server.wm.TaskWrapper createFromToken(@NonNull android.os.IBinder);
     method public com.android.server.wm.TaskWrapper getRootTask();
     method public com.android.server.wm.TaskDisplayAreaWrapper getTaskDisplayArea();
     method public int getUserId();
diff --git a/builtInServices/prebuilts/mu_imms-prebuilt.jar b/builtInServices/prebuilts/mu_imms-prebuilt.jar
index 488c919..f2d0a50 100644
--- a/builtInServices/prebuilts/mu_imms-prebuilt.jar
+++ b/builtInServices/prebuilts/mu_imms-prebuilt.jar
Binary files differ
diff --git a/builtInServices/src/com/android/internal/car/CarActivityInterceptor.java b/builtInServices/src/com/android/internal/car/CarActivityInterceptor.java
index 8cd67ef..81c6d0b 100644
--- a/builtInServices/src/com/android/internal/car/CarActivityInterceptor.java
+++ b/builtInServices/src/com/android/internal/car/CarActivityInterceptor.java
@@ -17,11 +17,15 @@
 
 import android.annotation.Nullable;
 import android.app.TaskInfo;
+import android.car.builtin.util.Slogf;
 import android.content.pm.ActivityInfo;
 
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.ActivityInterceptResultWrapper;
 import com.android.server.wm.ActivityInterceptorCallback;
 import com.android.server.wm.ActivityInterceptorInfoWrapper;
+import com.android.server.wm.CarActivityInterceptorInterface;
 import com.android.server.wm.CarActivityInterceptorUpdatable;
 
 /**
@@ -30,15 +34,28 @@
  * @hide
  */
 public final class CarActivityInterceptor implements ActivityInterceptorCallback {
+    private static final String TAG  = CarActivityInterceptor.class.getSimpleName();
     private CarActivityInterceptorUpdatable mCarActivityInterceptorUpdatable;
 
-    CarActivityInterceptor(CarActivityInterceptorUpdatable carActivityInterceptorUpdatable) {
+    public CarActivityInterceptor() {
+        mCarActivityInterceptorUpdatable = null;
+    }
+
+    /**
+     * Sets the given {@link CarActivityInterceptorUpdatable} which this internal class will
+     * communicate with.
+     */
+    public void setUpdatable(CarActivityInterceptorUpdatable carActivityInterceptorUpdatable) {
         mCarActivityInterceptorUpdatable = carActivityInterceptorUpdatable;
     }
 
     @Nullable
     @Override
     public ActivityInterceptResult onInterceptActivityLaunch(ActivityInterceptorInfo info) {
+        if (mCarActivityInterceptorUpdatable == null) {
+            Slogf.w(TAG, "mCarActivityInterceptorUpdatable not set");
+            return null;
+        }
         ActivityInterceptResultWrapper interceptResultWrapper = mCarActivityInterceptorUpdatable
                 .onInterceptActivityLaunch(ActivityInterceptorInfoWrapper.create(info));
         if (interceptResultWrapper == null) {
@@ -52,4 +69,22 @@
             ActivityInterceptorInfo info) {
         // do nothing
     }
+
+    CarActivityInterceptorInterface getBuiltinInterface() {
+        return new CarActivityInterceptorInterface() {
+            @Override
+            public int getUserAssignedToDisplay(int displayId) {
+                UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+                int userId = umi.getUserAssignedToDisplay(displayId);
+                return userId;
+            }
+
+            @Override
+            public int getMainDisplayAssignedToUser(int userId) {
+                UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+                int displayId = umi.getMainDisplayAssignedToUser(userId);
+                return displayId;
+            }
+        };
+    }
 }
diff --git a/builtInServices/src/com/android/internal/car/CarServiceHelperService.java b/builtInServices/src/com/android/internal/car/CarServiceHelperService.java
index 86cd965..b516c1e 100644
--- a/builtInServices/src/com/android/internal/car/CarServiceHelperService.java
+++ b/builtInServices/src/com/android/internal/car/CarServiceHelperService.java
@@ -75,6 +75,7 @@
 import com.android.server.utils.Slogf;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.CarActivityInterceptorInterface;
 import com.android.server.wm.CarLaunchParamsModifier;
 import com.android.server.wm.CarLaunchParamsModifierInterface;
 
@@ -158,6 +159,7 @@
     private boolean mSystemBootCompleted;
 
     private final CarLaunchParamsModifier mCarLaunchParamsModifier;
+    private final CarActivityInterceptor mCarActivityInterceptor;
 
     private final Handler mHandler;
     private final HandlerThread mHandlerThread = new HandlerThread("CarServiceHelperService");
@@ -206,15 +208,18 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
         mCarLaunchParamsModifier = carLaunchParamsModifier;
+        mCarActivityInterceptor = new CarActivityInterceptor();
         mCarWatchdogDaemonHelper = carWatchdogDaemonHelper;
         try {
             if (carServiceHelperServiceUpdatable == null) {
                 mCarServiceHelperServiceUpdatable = (CarServiceHelperServiceUpdatable) Class
                         .forName(CSHS_UPDATABLE_CLASSNAME_STRING)
                         .getConstructor(Context.class, CarServiceHelperInterface.class,
-                                CarLaunchParamsModifierInterface.class)
+                                CarLaunchParamsModifierInterface.class,
+                                CarActivityInterceptorInterface.class)
                         .newInstance(mContext, this,
-                                mCarLaunchParamsModifier.getBuiltinInterface());
+                                mCarLaunchParamsModifier.getBuiltinInterface(),
+                                mCarActivityInterceptor.getBuiltinInterface());
                 Slogf.d(TAG, "CarServiceHelperServiceUpdatable created via reflection.");
             } else {
                 mCarServiceHelperServiceUpdatable = carServiceHelperServiceUpdatable;
@@ -231,6 +236,8 @@
         }
         mCarLaunchParamsModifier.setUpdatable(
                 mCarServiceHelperServiceUpdatable.getCarLaunchParamsModifierUpdatable());
+        mCarActivityInterceptor.setUpdatable(mCarServiceHelperServiceUpdatable
+                .getCarActivityInterceptorUpdatable());
 
         UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
         if (umi != null) {
@@ -297,8 +304,7 @@
                     ActivityTaskManagerInternal.class);
             activityTaskManagerInternal.registerActivityStartInterceptor(
                     PRODUCT_ORDERED_ID,
-                    new CarActivityInterceptor(mCarServiceHelperServiceUpdatable
-                            .getCarActivityInterceptorUpdatable()));
+                    mCarActivityInterceptor);
             t.traceEnd();
         }
     }
diff --git a/builtInServices/src/com/android/server/wm/CarActivityInterceptorInterface.java b/builtInServices/src/com/android/server/wm/CarActivityInterceptorInterface.java
new file mode 100644
index 0000000..fed022e
--- /dev/null
+++ b/builtInServices/src/com/android/server/wm/CarActivityInterceptorInterface.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.RequiresApi;
+import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.car.builtin.annotation.PlatformVersion;
+import android.os.Build;
+
+import com.android.annotation.AddedIn;
+
+/**
+ * Interface implemented by {@link com.android.internal.car.CarActivityInterceptor} and used by
+ * {@link CarActivityInterceptorUpdatable}.
+ *
+ * Because {@code CarActivityInterceptorUpdatable} calls {@code CarActivityInterceptorInterface}
+ * with {@code mLock} acquired, {@code CarActivityInterceptorInterface} shouldn't call
+ * {@code CarActivityInterceptorUpdatable} again during its execution.
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public interface CarActivityInterceptorInterface {
+    /**
+     * Returns the main user (i.e., not a profile) that is assigned to the display, or the
+     * {@link android.app.ActivityManager#getCurrentUser() current foreground user} if no user is
+     * associated with the display.
+     * See {@link com.android.server.pm.UserManagerInternal#getUserAssignedToDisplay(int)} for
+     * the detail.
+     */
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @UserIdInt int getUserAssignedToDisplay(int displayId);
+
+    /**
+     * Returns the main display id assigned to the user, or {@code Display.INVALID_DISPLAY} if the
+     * user is not assigned to any main display.
+     * See {@link com.android.server.pm.UserManagerInternal#getMainDisplayAssignedToUser(int)} for
+     * the detail.
+     */
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    int getMainDisplayAssignedToUser(@UserIdInt int userId);
+}
diff --git a/builtInServices/src/com/android/server/wm/TaskWrapper.java b/builtInServices/src/com/android/server/wm/TaskWrapper.java
index 4f721bf..089a6eb 100644
--- a/builtInServices/src/com/android/server/wm/TaskWrapper.java
+++ b/builtInServices/src/com/android/server/wm/TaskWrapper.java
@@ -16,9 +16,14 @@
 
 package com.android.server.wm;
 
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresApi;
 import android.annotation.SystemApi;
 import android.car.builtin.annotation.PlatformVersion;
+import android.os.IBinder;
 
 import com.android.annotation.AddedIn;
 
@@ -41,6 +46,13 @@
         return new TaskWrapper(task);
     }
 
+    /** Creates an instance of {@link TaskWrapper} based on the task's remote {@code token}. */
+    @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
+    @RequiresApi(UPSIDE_DOWN_CAKE)
+    public static TaskWrapper createFromToken(@NonNull IBinder token) {
+        return new TaskWrapper((Task) WindowContainer.fromBinder(token));
+    }
+
     /**
      * Gets the {@code userId} of this {@link Task} is created for
      */
diff --git a/builtInServices/src_imms/com/android/server/inputmethod/CarDefaultImeVisibilityApplier.java b/builtInServices/src_imms/com/android/server/inputmethod/CarDefaultImeVisibilityApplier.java
index fbf08e2..0b7f4c4 100644
--- a/builtInServices/src_imms/com/android/server/inputmethod/CarDefaultImeVisibilityApplier.java
+++ b/builtInServices/src_imms/com/android/server/inputmethod/CarDefaultImeVisibilityApplier.java
@@ -23,8 +23,10 @@
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_REMOVE_IME_SNAPSHOT;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_SNAPSHOT;
 
 import android.annotation.Nullable;
 import android.os.IBinder;
@@ -163,6 +165,12 @@
                 mService.showCurrentInputLocked(windowToken, statsToken,
                         InputMethodManager.SHOW_IMPLICIT, null, reason);
                 break;
+            case STATE_SHOW_IME_SNAPSHOT:
+                showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked(), null);
+                break;
+            case STATE_REMOVE_IME_SNAPSHOT:
+                removeImeScreenshot(mService.getDisplayIdToShowImeLocked());
+                break;
             default:
                 throw new IllegalArgumentException("Invalid IME visibility state: " + state);
         }
diff --git a/builtInServices/src_imms/com/android/server/inputmethod/CarImeVisibilityStateComputer.java b/builtInServices/src_imms/com/android/server/inputmethod/CarImeVisibilityStateComputer.java
index cbfdecc..101709e 100644
--- a/builtInServices/src_imms/com/android/server/inputmethod/CarImeVisibilityStateComputer.java
+++ b/builtInServices/src_imms/com/android/server/inputmethod/CarImeVisibilityStateComputer.java
@@ -16,6 +16,7 @@
 
 package com.android.server.inputmethod;
 
+
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
 import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
 import static android.server.inputmethod.InputMethodManagerServiceProto.INPUT_SHOWN;
@@ -27,8 +28,11 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
 import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
 import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.server.inputmethod.CarInputMethodManagerService.computeImeDisplayIdForTarget;
 
 import android.accessibilityservice.AccessibilityService;
@@ -49,6 +53,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.server.LocalServices;
+import com.android.server.wm.ImeTargetChangeListener;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.io.PrintWriter;
@@ -61,7 +66,7 @@
  */
 public final class CarImeVisibilityStateComputer {
 
-    private static final String TAG = "CarImeVisibilityStateComputer";
+    private static final String TAG = "ImeVisibilityStateComputer";
 
     private static final boolean DEBUG = CarInputMethodManagerService.DEBUG;
 
@@ -99,6 +104,18 @@
      */
     private boolean mInputShown;
 
+    /**
+     * Set if we called
+     * {@link com.android.server.wm.ImeTargetVisibilityPolicy#showImeScreenshot(IBinder, int)}.
+     */
+    private boolean mRequestedImeScreenshot;
+
+    /** The window token of the current visible IME layering target overlay. */
+    private IBinder mCurVisibleImeLayeringOverlay;
+
+    /** The window token of the current visible IME input target. */
+    private IBinder mCurVisibleImeInputTarget;
+
     /** Represent the invalid IME visibility state */
     public static final int STATE_INVALID = -1;
 
@@ -122,6 +139,10 @@
     public static final int STATE_HIDE_IME_NOT_ALWAYS = 6;
 
     public static final int STATE_SHOW_IME_IMPLICIT = 7;
+
+    /** State to handle removing an IME preview surface when necessary. */
+    public static final int STATE_REMOVE_IME_SNAPSHOT = 8;
+
     @IntDef({
             STATE_INVALID,
             STATE_HIDE_IME,
@@ -132,6 +153,7 @@
             STATE_HIDE_IME_EXPLICIT,
             STATE_HIDE_IME_NOT_ALWAYS,
             STATE_SHOW_IME_IMPLICIT,
+            STATE_REMOVE_IME_SNAPSHOT,
     })
     @interface VisibilityState {}
 
@@ -172,6 +194,30 @@
         mWindowManagerInternal = wmService;
         mImeDisplayValidator = imeDisplayValidator;
         mPolicy = imePolicy;
+        mWindowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() {
+            @Override
+            public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken,
+                    @WindowManager.LayoutParams.WindowType int windowType, boolean visible,
+                    boolean removed) {
+                mCurVisibleImeLayeringOverlay =
+                        // Ignoring the starting window since it's ok to cover the IME target
+                        // window in temporary without affecting the IME visibility.
+                        (visible && !removed && windowType != TYPE_APPLICATION_STARTING)
+                                ? overlayWindowToken : null;
+            }
+
+            @Override
+            public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget,
+                    boolean visibleRequested, boolean removed) {
+                if (mCurVisibleImeInputTarget == imeInputTarget && (!visibleRequested || removed)
+                        && mCurVisibleImeLayeringOverlay != null) {
+                    mService.onApplyImeVisibilityFromComputer(imeInputTarget,
+                            new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                                    SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE));
+                }
+                mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null;
+            }
+        });
     }
 
     /**
@@ -284,7 +330,7 @@
 
     void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
         final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
-        if (state != null && newState.hasEdiorFocused()) {
+        if (state != null && newState.hasEditorFocused()) {
             // Inherit the last requested IME visible state when the target window is still
             // focused with an editor.
             newState.setRequestedImeVisible(state.mRequestedImeVisible);
@@ -342,7 +388,7 @@
         // state is ALWAYS_HIDDEN or STATE_HIDDEN with forward navigation).
         // Because the app might leverage these flags to hide soft-keyboard with showing their own
         // UI for input.
-        if (state.hasEdiorFocused() && shouldRestoreImeVisibility(state)) {
+        if (state.hasEditorFocused() && shouldRestoreImeVisibility(state)) {
             if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
             // Inherit the last requested IME visible state when the target window is still
             // focused with an editor.
@@ -354,7 +400,7 @@
 
         switch (softInputVisibility) {
             case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
-                if (state.hasImeFocusChanged() && (!state.hasEdiorFocused() || !doAutoShow)) {
+                if (state.hasImeFocusChanged() && (!state.hasEditorFocused() || !doAutoShow)) {
                     if (WindowManager.LayoutParams.mayUseInputMethod(state.getWindowFlags())) {
                         // There is no focus view, and this window will
                         // be behind any soft input window, so hide the
@@ -363,7 +409,7 @@
                         return new ImeVisibilityResult(STATE_HIDE_IME_NOT_ALWAYS,
                                 SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
                     }
-                } else if (state.hasEdiorFocused() && doAutoShow && isForwardNavigation) {
+                } else if (state.hasEditorFocused() && doAutoShow && isForwardNavigation) {
                     // There is a focus view, and we are navigating forward
                     // into the window, so show the input window for the user.
                     // We only do this automatically if the window can resize
@@ -439,7 +485,7 @@
                         SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
             }
         }
-        if (!state.hasEdiorFocused() && mInputShown && state.isStartInputByGainFocus()
+        if (!state.hasEditorFocused() && mInputShown && state.isStartInputByGainFocus()
                 && mService.mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) {
             // Hide the soft-keyboard when the system do nothing for softInputModeState
             // of the window being gained focus without an editor. This behavior benefits
@@ -455,6 +501,21 @@
         return null;
     }
 
+    @VisibleForTesting
+    ImeVisibilityResult onInteractiveChanged(IBinder windowToken, boolean interactive) {
+        final ImeTargetWindowState state = getWindowStateOrNull(windowToken);
+        if (state != null && state.isRequestedImeVisible() && mInputShown && !interactive) {
+            mRequestedImeScreenshot = true;
+            return new ImeVisibilityResult(STATE_SHOW_IME_SNAPSHOT, SHOW_IME_SCREENSHOT_FROM_IMMS);
+        }
+        if (interactive && mRequestedImeScreenshot) {
+            mRequestedImeScreenshot = false;
+            return new ImeVisibilityResult(STATE_REMOVE_IME_SNAPSHOT,
+                    REMOVE_IME_SCREENSHOT_FROM_IMMS);
+        }
+        return null;
+    }
+
     IBinder getWindowTokenFrom(IBinder requestImeToken) {
         for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
             final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
@@ -622,7 +683,7 @@
             return mImeFocusChanged;
         }
 
-        boolean hasEdiorFocused() {
+        boolean hasEditorFocused() {
             return mHasFocusedEditor;
         }
 
diff --git a/builtInServices/src_imms/com/android/server/inputmethod/CarInputMethodManagerService.java b/builtInServices/src_imms/com/android/server/inputmethod/CarInputMethodManagerService.java
index 0ee37ee..967fa0d 100644
--- a/builtInServices/src_imms/com/android/server/inputmethod/CarInputMethodManagerService.java
+++ b/builtInServices/src_imms/com/android/server/inputmethod/CarInputMethodManagerService.java
@@ -863,13 +863,15 @@
     @GuardedBy("ImfLock.class")
     private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
 
-    private static final class SoftInputShowHideHistory {
+    @VisibleForTesting
+    static final class SoftInputShowHideHistory {
         private final Entry[] mEntries = new Entry[16];
         private int mNextIndex = 0;
         private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
 
-        private static final class Entry {
+        static final class Entry {
             final int mSequenceNumber = sSequenceNumber.getAndIncrement();
+            @Nullable
             final ClientState mClientState;
             @SoftInputModeFlags
             final int mFocusedWindowSoftInputMode;
@@ -881,7 +883,7 @@
             final boolean mInFullscreenMode;
             @NonNull
             final String mFocusedWindowName;
-            @NonNull
+            @Nullable
             final EditorInfo mEditorInfo;
             @NonNull
             final String mRequestWindowName;
@@ -960,9 +962,13 @@
 
                 pw.print(prefix);
                 pw.print(" editorInfo: ");
-                pw.print(" inputType=" + entry.mEditorInfo.inputType);
-                pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
-                pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+                if (entry.mEditorInfo != null) {
+                    pw.print(" inputType=" + entry.mEditorInfo.inputType);
+                    pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
+                    pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
+                } else {
+                    pw.println("null");
+                }
 
                 pw.print(prefix);
                 pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
@@ -4812,6 +4818,14 @@
         }
     }
 
+    void onApplyImeVisibilityFromComputer(IBinder windowToken,
+            @NonNull ImeVisibilityResult result) {
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(windowToken, null, result.getState(),
+                    result.getReason());
+        }
+    }
+
     @GuardedBy("ImfLock.class")
     void setEnabledSessionLocked(SessionState session) {
         if (mEnabledSession != session) {
@@ -5048,6 +5062,14 @@
                 return;
             }
             if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) {
+                // Handle IME visibility when interactive changed before finishing the input to
+                // ensure we preserve the last state as possible.
+                final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
+                        mCurFocusedWindow, interactive);
+                if (imeVisRes != null) {
+                    mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null,
+                            imeVisRes.getState(), imeVisRes.getReason());
+                }
                 // Eligible IME processes use new "setInteractive" protocol.
                 mCurClient.mClient.setInteractive(mIsInteractive, mInFullscreenMode);
             } else {
diff --git a/builtInServices/src_imms/com/android/server/inputmethod/InputMethodManagerServiceProxy.java b/builtInServices/src_imms/com/android/server/inputmethod/InputMethodManagerServiceProxy.java
index 7802719..e7bb329 100644
--- a/builtInServices/src_imms/com/android/server/inputmethod/InputMethodManagerServiceProxy.java
+++ b/builtInServices/src_imms/com/android/server/inputmethod/InputMethodManagerServiceProxy.java
@@ -77,8 +77,6 @@
 /**
  * Proxy used to host IMMSs per user and reroute requests to the user associated IMMS.
  *
- * TODO(b/245798405): Add the logic to handle user 0
- *
  * @hide
  */
 public final class InputMethodManagerServiceProxy extends IInputMethodManager.Stub {
@@ -397,22 +395,32 @@
             mServicesForUser.get(userIdArg).dump(fd, pw, args);
             return;
         }
-
         pw.println("*InputMethodManagerServiceProxy");
+        pw.println("**mServicesForUser**");
         try {
             mRwLock.readLock().lock();
-            pw.println("**mServicesForUser**");
-            for (int i = 0; i < mServicesForUser.size(); i++) {
-                int userId = mServicesForUser.keyAt(i);
-                CarInputMethodManagerService imms = mServicesForUser.valueAt(i);
-                pw.println(" userId=" + userId + " imms=" + imms.hashCode() + " {autofill="
-                        + imms.getAutofillController() + "}");
-            }
-            pw.println("**mLocalServicesForUser**");
-            for (int i = 0; i < mLocalServicesForUser.size(); i++) {
-                int userId = mLocalServicesForUser.keyAt(i);
-                InputMethodManagerInternal immi = mLocalServicesForUser.valueAt(i);
-                pw.println(" userId=" + userId + " immi=" + immi.hashCode());
+            if (parseBriefArg(args)) {
+                // Dump brief
+                for (int i = 0; i < mServicesForUser.size(); i++) {
+                    int userId = mServicesForUser.keyAt(i);
+                    CarInputMethodManagerService imms = mServicesForUser.valueAt(i);
+                    pw.println(" userId=" + userId + " imms=" + imms.hashCode() + " {autofill="
+                            + imms.getAutofillController() + "}");
+                }
+                pw.println("**mLocalServicesForUser**");
+                for (int i = 0; i < mLocalServicesForUser.size(); i++) {
+                    int userId = mLocalServicesForUser.keyAt(i);
+                    InputMethodManagerInternal immi = mLocalServicesForUser.valueAt(i);
+                    pw.println(" userId=" + userId + " immi=" + immi.hashCode());
+                }
+            } else {
+                // Dump full
+                for (int i = 0; i < mServicesForUser.size(); i++) {
+                    int userId = mServicesForUser.keyAt(i);
+                    pw.println("**CarInputMethodManagerService for userId=" + userId);
+                    CarInputMethodManagerService imms = mServicesForUser.valueAt(i);
+                    imms.dump(fd, pw, args);
+                }
             }
         } finally {
             mRwLock.readLock().unlock();
@@ -420,6 +428,18 @@
         pw.flush();
     }
 
+    private boolean parseBriefArg(String[] args) {
+        if (args == null) {
+            return false;
+        }
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equals("--brief")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Parse the args string and returns the value of `--user` argument. Returns
      * {@link UserHandle.USER_NULL} in case of `--user` is not in args.
@@ -571,9 +591,11 @@
                 windowFlags, editorInfo, inputConnection,
                 remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId,
                 imeDispatcher);
-        Slogf.d(IMMS_TAG, "Returning {%s} for startInputOrWindowGainedFocus / user {%d}",
-                result,
-                userId);
+        if (DBG) {
+            Slogf.d(IMMS_TAG, "Returning {%s} for startInputOrWindowGainedFocus / user {%d}",
+                    result,
+                    userId);
+        }
         return result;
     }
 
diff --git a/builtInServices/tests/res/raw/CSHS_classes.txt b/builtInServices/tests/res/raw/CSHS_classes.txt
index 2996485..d584c38 100644
--- a/builtInServices/tests/res/raw/CSHS_classes.txt
+++ b/builtInServices/tests/res/raw/CSHS_classes.txt
@@ -13,3 +13,4 @@
 com.android.server.wm.ActivityOptionsWrapper
 com.android.server.wm.ActivityRecordWrapper
 com.android.server.wm.RequestWrapper
+com.android.server.wm.CarActivityInterceptorInterface
diff --git a/updatableServices/Android.bp b/updatableServices/Android.bp
index 16947a1..3069027 100644
--- a/updatableServices/Android.bp
+++ b/updatableServices/Android.bp
@@ -27,7 +27,7 @@
     ],
 
     sdk_version: "module_current",
-    min_sdk_version: "31",
+    min_sdk_version: "33",
     apex_available: [
         "//apex_available:platform",
         "com.android.car.framework"
diff --git a/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java b/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java
index 6fd1ce3..5e6a746 100644
--- a/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java
+++ b/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java
@@ -52,6 +52,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.car.CarServiceHelperInterface;
 import com.android.internal.car.CarServiceHelperServiceUpdatable;
+import com.android.server.wm.CarActivityInterceptorInterface;
 import com.android.server.wm.CarActivityInterceptorUpdatableImpl;
 import com.android.server.wm.CarLaunchParamsModifierInterface;
 import com.android.server.wm.CarLaunchParamsModifierUpdatable;
@@ -108,17 +109,30 @@
     private final CarLaunchParamsModifierUpdatableImpl mCarLaunchParamsModifierUpdatable;
     private final CarActivityInterceptorUpdatableImpl mCarActivityInterceptorUpdatable;
 
+    /**
+     * This constructor is meant to be called using reflection by the builtin service and hence it
+     * shouldn't be changed as it is called from the platform with version {@link TIRAMISU}.
+     */
     public CarServiceHelperServiceUpdatableImpl(Context context,
             CarServiceHelperInterface carServiceHelperInterface,
             CarLaunchParamsModifierInterface carLaunchParamsModifierInterface) {
         this(context, carServiceHelperInterface, carLaunchParamsModifierInterface,
-                /* carServiceProxy= */ null);
+                /* carActivityInterceptorInterface= */ null);
+    }
+
+    public CarServiceHelperServiceUpdatableImpl(Context context,
+            CarServiceHelperInterface carServiceHelperInterface,
+            CarLaunchParamsModifierInterface carLaunchParamsModifierInterface,
+            CarActivityInterceptorInterface carActivityInterceptorInterface) {
+        this(context, carServiceHelperInterface, carLaunchParamsModifierInterface,
+                carActivityInterceptorInterface, /* carServiceProxy= */ null);
     }
 
     @VisibleForTesting
     CarServiceHelperServiceUpdatableImpl(Context context,
             CarServiceHelperInterface carServiceHelperInterface,
             CarLaunchParamsModifierInterface carLaunchParamsModifierInterface,
+            @Nullable CarActivityInterceptorInterface carActivityInterceptorInterface,
             @Nullable CarServiceProxy carServiceProxy) {
         mContext = context;
         mHandlerThread.start();
@@ -127,7 +141,8 @@
         mCarLaunchParamsModifierUpdatable = new CarLaunchParamsModifierUpdatableImpl(
                 carLaunchParamsModifierInterface);
         if (isPlatformVersionAtLeastU()) {
-            mCarActivityInterceptorUpdatable = new CarActivityInterceptorUpdatableImpl();
+            mCarActivityInterceptorUpdatable = new CarActivityInterceptorUpdatableImpl(
+                    (CarActivityInterceptorInterface) carActivityInterceptorInterface);
         } else {
             mCarActivityInterceptorUpdatable = null;
         }
diff --git a/updatableServices/src/com/android/server/wm/CarActivityInterceptorUpdatableImpl.java b/updatableServices/src/com/android/server/wm/CarActivityInterceptorUpdatableImpl.java
index fbb2762..ee0d999 100644
--- a/updatableServices/src/com/android/server/wm/CarActivityInterceptorUpdatableImpl.java
+++ b/updatableServices/src/com/android/server/wm/CarActivityInterceptorUpdatableImpl.java
@@ -16,9 +16,13 @@
 
 package com.android.server.wm;
 
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
 import android.annotation.NonNull;
+import android.annotation.RequiresApi;
 import android.annotation.SystemApi;
 import android.app.ActivityOptions;
+import android.car.builtin.util.Slogf;
 import android.content.ComponentName;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -38,13 +42,21 @@
  *
  * @hide
  */
+@RequiresApi(UPSIDE_DOWN_CAKE)
 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class CarActivityInterceptorUpdatableImpl implements CarActivityInterceptorUpdatable {
+    public static final String TAG = CarActivityInterceptorUpdatableImpl.class.getSimpleName();
+
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private final ArrayMap<ComponentName, IBinder> mActivityToRootTaskMap = new ArrayMap<>();
     @GuardedBy("mLock")
     private final Set<IBinder> mKnownRootTasks = new ArraySet<>();
+    private final CarActivityInterceptorInterface mBuiltIn;
+
+    public CarActivityInterceptorUpdatableImpl(CarActivityInterceptorInterface builtInInterface) {
+        mBuiltIn = builtInInterface;
+    }
 
     @Override
     public ActivityInterceptResultWrapper onInterceptActivityLaunch(
@@ -57,11 +69,16 @@
         synchronized (mLock) {
             int keyIndex = mActivityToRootTaskMap.indexOfKey(componentName);
             if (keyIndex >= 0) {
+                IBinder rootTaskToken = mActivityToRootTaskMap.valueAt(keyIndex);
+                if (!isRootTaskUserSameAsActivityUser(rootTaskToken, info)) {
+                    return null;
+                }
+
                 ActivityOptionsWrapper optionsWrapper = info.getCheckedOptions();
                 if (optionsWrapper == null) {
                     optionsWrapper = ActivityOptionsWrapper.create(ActivityOptions.makeBasic());
                 }
-                optionsWrapper.setLaunchRootTask(mActivityToRootTaskMap.valueAt(keyIndex));
+                optionsWrapper.setLaunchRootTask(rootTaskToken);
                 return ActivityInterceptResultWrapper.create(info.getIntent(),
                         optionsWrapper.getOptions());
             }
@@ -69,6 +86,21 @@
         return null;
     }
 
+    private boolean isRootTaskUserSameAsActivityUser(IBinder rootTaskToken,
+            ActivityInterceptorInfoWrapper activityInterceptorInfoWrapper) {
+        TaskWrapper rootTask = TaskWrapper.createFromToken(rootTaskToken);
+        int userIdFromActivity = activityInterceptorInfoWrapper.getUserId();
+        int userIdFromRootTask = mBuiltIn.getUserAssignedToDisplay(rootTask
+                .getTaskDisplayArea().getDisplay().getDisplayId());
+        if (userIdFromActivity == userIdFromRootTask) {
+            return true;
+        }
+        Slogf.w(TAG, "The user id of launched activity (%d) doesn't match the "
+                + "user id which the display (which the root task is added in) is "
+                + "assigned to (%d).", userIdFromActivity, userIdFromRootTask);
+        return false;
+    }
+
     /**
      * Sets the given {@code activities} to be persistent on the root task corresponding to the
      * given {@code rootTaskToken}.
diff --git a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java b/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java
index 40f4787..d608e12 100644
--- a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java
+++ b/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java
@@ -40,6 +40,7 @@
 
 import com.android.car.internal.util.VersionUtils;
 import com.android.internal.car.CarServiceHelperInterface;
+import com.android.server.wm.CarActivityInterceptorInterface;
 import com.android.server.wm.CarLaunchParamsModifierInterface;
 
 import org.junit.Before;
@@ -68,6 +69,8 @@
     @Mock
     private CarLaunchParamsModifierInterface mCarLaunchParamsModifierInterface;
     @Mock
+    private CarActivityInterceptorInterface mCarActivityInterceptorInterface;
+    @Mock
     private ICar mICarBinder;
     @Mock
     private IBinder mIBinder;
@@ -84,6 +87,7 @@
                 mMockContext,
                 mCarServiceHelperInterface,
                 mCarLaunchParamsModifierInterface,
+                mCarActivityInterceptorInterface,
                 mCarServiceProxy);
     }
 
diff --git a/updatableServices/tests/src/com/android/server/wm/CarActivityInterceptorUpdatableTest.java b/updatableServices/tests/src/com/android/server/wm/CarActivityInterceptorUpdatableTest.java
index c6bf0f1..339616b 100644
--- a/updatableServices/tests/src/com/android/server/wm/CarActivityInterceptorUpdatableTest.java
+++ b/updatableServices/tests/src/com/android/server/wm/CarActivityInterceptorUpdatableTest.java
@@ -20,11 +20,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
 import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ResolveInfo;
+import android.view.Display;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -40,15 +43,39 @@
 
 @RunWith(AndroidJUnit4.class)
 public class CarActivityInterceptorUpdatableTest {
+    private static final int DEFAULT_CURRENT_USER_ID = 112;
+    private static final int PASSENGER_USER_ID = 198;
     private CarActivityInterceptorUpdatableImpl mInterceptor;
     private MockitoSession mMockingSession;
     private WindowContainer.RemoteToken mRootTaskToken1;
     private WindowContainer.RemoteToken mRootTaskToken2;
 
     @Mock
-    private WindowContainer mWindowContainer1;
+    private Task mWindowContainer1;
     @Mock
-    private WindowContainer mWindowContainer2;
+    private Task mWindowContainer2;
+
+    @Mock
+    private DisplayContent mDisplayContent;
+
+    @Mock
+    private Display mDisplay;
+
+    @Mock
+    private TaskDisplayArea mTda;
+
+    private final CarActivityInterceptorInterface mCarActivityInterceptorInterface =
+            new CarActivityInterceptorInterface() {
+                @Override
+                public int getUserAssignedToDisplay(int displayId) {
+                    return DEFAULT_CURRENT_USER_ID;
+                }
+
+                @Override
+                public int getMainDisplayAssignedToUser(int userId) {
+                    return 0;
+                }
+            };
 
     @Before
     public void setUp() {
@@ -57,12 +84,19 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
+        mTda.mDisplayContent = mDisplayContent;
+        when(mDisplayContent.getDisplay()).thenReturn(mDisplay);
+        when(mDisplay.getDisplayId()).thenReturn(0);
+
         mRootTaskToken1 = new WindowContainer.RemoteToken(mWindowContainer1);
         mWindowContainer1.mRemoteToken = mRootTaskToken1;
+        when(mWindowContainer1.getTaskDisplayArea()).thenReturn(mTda);
+
         mRootTaskToken2 = new WindowContainer.RemoteToken(mWindowContainer2);
+        when(mWindowContainer2.getTaskDisplayArea()).thenReturn(mTda);
         mWindowContainer2.mRemoteToken = mRootTaskToken2;
 
-        mInterceptor = new CarActivityInterceptorUpdatableImpl();
+        mInterceptor = new CarActivityInterceptorUpdatableImpl(mCarActivityInterceptorInterface);
     }
 
     @After
@@ -74,15 +108,15 @@
     }
 
     private ActivityInterceptorInfoWrapper createActivityInterceptorInfo(String packageName,
-            String activityName, Intent intent, ActivityOptions options) {
+            String activityName, Intent intent, ActivityOptions options, int userId) {
         ActivityInfo activityInfo = new ActivityInfo();
         activityInfo.packageName = packageName;
         activityInfo.name = activityName;
         ActivityInterceptorCallback.ActivityInterceptorInfo.Builder builder =
                 new ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(
                         /* callingUId= */ 0, /* callingPid= */ 0, /* realCallingUid= */ 0,
-                        /* realCallingPid= */ 0, /* userId= */ 56, intent, new ResolveInfo(),
-                        activityInfo);
+                        /* realCallingPid= */ 0, /* userId= */ userId, intent,
+                        new ResolveInfo(), activityInfo);
         builder.setCheckedOptions(options);
         return ActivityInterceptorInfoWrapper.create(builder.build());
     }
@@ -90,7 +124,13 @@
     private ActivityInterceptorInfoWrapper createActivityInterceptorInfoWithCustomIntent(
             String packageName, String activityName, Intent intent) {
         return createActivityInterceptorInfo(packageName, activityName, intent,
-                ActivityOptions.makeBasic());
+                ActivityOptions.makeBasic(), DEFAULT_CURRENT_USER_ID);
+    }
+
+    private ActivityInterceptorInfoWrapper createActivityInterceptorInfoWithCustomIntent(
+            String packageName, String activityName, Intent intent, int userId) {
+        return createActivityInterceptorInfo(packageName, activityName, intent,
+                ActivityOptions.makeBasic(), userId);
     }
 
     private ActivityInterceptorInfoWrapper createActivityInterceptorInfoWithMainIntent(
@@ -101,10 +141,19 @@
     }
 
     private ActivityInterceptorInfoWrapper createActivityInterceptorInfoWithMainIntent(
+            String packageName, String activityName, int userId) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(ComponentName.unflattenFromString(packageName + "/" + activityName));
+        return createActivityInterceptorInfoWithCustomIntent(packageName, activityName, intent,
+                userId);
+    }
+
+    private ActivityInterceptorInfoWrapper createActivityInterceptorInfoWithMainIntent(
             String packageName, String activityName, ActivityOptions options) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setComponent(ComponentName.unflattenFromString(packageName + "/" + activityName));
-        return createActivityInterceptorInfo(packageName, activityName, intent, options);
+        return createActivityInterceptorInfo(packageName, activityName, intent, options,
+                DEFAULT_CURRENT_USER_ID);
     }
 
     @Test
@@ -177,6 +226,23 @@
     }
 
     @Test
+    public void interceptActivityLaunch_persistedActivity_differentUser_doesNothing() {
+        List<ComponentName> activities = List.of(
+                ComponentName.unflattenFromString("com.example.app/com.example.app.MainActivity"),
+                ComponentName.unflattenFromString("com.example.app2/com.example.app2.MainActivity")
+        );
+        mInterceptor.setPersistentActivityOnRootTask(activities, mRootTaskToken1);
+        ActivityInterceptorInfoWrapper info =
+                createActivityInterceptorInfoWithMainIntent(activities.get(0).getPackageName(),
+                        activities.get(0).getClassName(), /* userId= */ PASSENGER_USER_ID);
+
+        ActivityInterceptResultWrapper result =
+                mInterceptor.onInterceptActivityLaunch(info);
+
+        assertThat(result).isNull();
+    }
+
+    @Test
     public void setPersistentActivity_nullLaunchRootTask_removesAssociation() {
         List<ComponentName> activities1 = List.of(
                 ComponentName.unflattenFromString("com.example.app/com.example.app.MainActivity"),