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"),