diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 2b579d09d3a22..ef0c19c8dc02b 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -16,20 +16,57 @@ package android.view; +import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.Region; import android.gui.TouchOcclusionMode; import android.os.IBinder; +import android.os.InputConfig; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; /** - * Functions as a handle for a window that can receive input. - * Enables the native input dispatcher to refer indirectly to the window manager's window state. + * Functions as a handle for a window that can receive input, and allows for the behavior of the + * input window to be configured. * @hide */ public final class InputWindowHandle { + + /** + * An internal annotation for all the {@link android.os.InputConfig} flags that can be + * specified to {@link #inputConfig} to control the behavior of an input window. Only the + * flags listed here are valid for use in Java. + * + * The default flag value is 0, which is what we expect for a normal application window. Adding + * a flag indicates that the window's behavior deviates from that of a normal application + * window. + * + * The flags are defined as an AIDL enum to keep it in sync with native code. + * {@link android.os.InputConfig} flags that are not listed here should not be used in Java, and + * are only meant to be used in native code. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + InputConfig.DEFAULT, + InputConfig.NO_INPUT_CHANNEL, + InputConfig.NOT_FOCUSABLE, + InputConfig.NOT_TOUCHABLE, + InputConfig.PREVENT_SPLITTING, + InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER, + InputConfig.IS_WALLPAPER, + InputConfig.PAUSE_DISPATCHING, + InputConfig.TRUSTED_OVERLAY, + InputConfig.WATCH_OUTSIDE_TOUCH, + InputConfig.SLIPPERY, + InputConfig.DISABLE_USER_ACTIVITY, + InputConfig.SPY, + InputConfig.INTERCEPTS_STYLUS, + }) + public @interface InputConfigFlags {} + // Pointer to the native input window handle. // This field is lazily initialized via JNI. @SuppressWarnings("unused") @@ -56,7 +93,8 @@ public final class InputWindowHandle { // The window name. public String name; - // Window layout params attributes. (WindowManager.LayoutParams) + // Window layout params attributes. (WindowManager.LayoutParams) + // These values do not affect any input configurations. Use {@link #inputConfig} instead. public int layoutParamsFlags; public int layoutParamsType; @@ -78,20 +116,9 @@ public final class InputWindowHandle { // Window touchable region. public final Region touchableRegion = new Region(); - // Window is visible. - public boolean visible; - - // Window can be focused. - public boolean focusable; - - // Window has wallpaper. (window is the current wallpaper target) - public boolean hasWallpaper; - - // Input event dispatching is paused. - public boolean paused; - - // Window is trusted overlay. - public boolean trustedOverlay; + // Flags that specify the behavior of this input window. See {@link #InputConfigFlags}. + @InputConfigFlags + public int inputConfig; // What effect this window has on touch occlusion if it lets touches pass through // By default windows will block touches if they are untrusted and from a different UID due to @@ -105,25 +132,21 @@ public final class InputWindowHandle { // Owner package of the window public String packageName; - // Window input features. - public int inputFeatures; - - // Display this input is on. + // Display this input window is on. public int displayId; /** - * Crops the touchable region to the bounds of the surface provided. + * Crops the {@link #touchableRegion} to the bounds of the surface provided. * - * This can be used in cases where the window is not - * {@link android.view.WindowManager#FLAG_NOT_TOUCH_MODAL} but should be constrained to the - * bounds of a parent window. That is the window should receive touch events outside its - * window but be limited to its stack bounds, such as in the case of split screen. + * This can be used in cases where the window should be constrained to the bounds of a parent + * window. That is, the window should receive touch events outside its window frame, but be + * limited to its stack bounds, such as in the case of split screen. */ public WeakReference touchableRegionSurfaceControl = new WeakReference<>(null); /** - * Replace {@link touchableRegion} with the bounds of {@link touchableRegionSurfaceControl}. If - * the handle is {@code null}, the bounds of the surface associated with this window is used + * Replace {@link #touchableRegion} with the bounds of {@link #touchableRegionSurfaceControl}. + * If the handle is {@code null}, the bounds of the surface associated with this window is used * as the touchable region. */ public boolean replaceTouchableRegionWithCrop; @@ -147,7 +170,6 @@ public final class InputWindowHandle { .append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",") .append(frameRight).append(",").append(frameBottom).append("]") .append(", touchableRegion=").append(touchableRegion) - .append(", visible=").append(visible) .append(", scaleFactor=").append(scaleFactor) .append(", transform=").append(transform) .append(", windowToken=").append(windowToken) @@ -165,11 +187,11 @@ public final class InputWindowHandle { } /** - * Set the window touchable region to the bounds of {@link touchableRegionBounds} ignoring any - * touchable region provided. + * Set the window's touchable region to the bounds of {@link #touchableRegionSurfaceControl} + * and ignore the value of {@link #touchableRegion}. * - * @param bounds surface to set the touchable region to. Set to {@code null} to set the bounds - * to the current surface. + * @param bounds surface to set the touchable region to. Set to {@code null} to set the + * touchable region as the current surface bounds. */ public void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) { setTouchableRegionCrop(bounds); @@ -195,4 +217,17 @@ public final class InputWindowHandle { window = IWindow.Stub.asInterface(windowToken); return window; } + + /** + * Set the provided inputConfig flag values. + * @param inputConfig the flag values to change + * @param value the provided flag values are set when true, and cleared when false + */ + public void setInputConfig(@InputConfigFlags int inputConfig, boolean value) { + if (value) { + this.inputConfig |= inputConfig; + return; + } + this.inputConfig &= ~inputConfig; + } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index dbfae46a6e724..45169efd7d356 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -106,7 +106,6 @@ import android.graphics.Region; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.os.IInputConstants; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -3360,8 +3359,7 @@ public interface WindowManager extends ViewManager { * * @hide */ - public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = - IInputConstants.InputFeature.NO_INPUT_CHANNEL; + public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 1 << 0; /** * When this window has focus, does not call user activity for all input events so @@ -3374,58 +3372,43 @@ public interface WindowManager extends ViewManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = - IInputConstants.InputFeature.DISABLE_USER_ACTIVITY; + public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 1 << 1; /** * An input spy window. This window will receive all pointer events within its touchable - * area, but will will not stop events from being sent to other windows below it in z-order. + * area, but will not stop events from being sent to other windows below it in z-order. * An input event will be dispatched to all spy windows above the top non-spy window at the * event's coordinates. - * @hide - */ - public static final int INPUT_FEATURE_SPY = - IInputConstants.InputFeature.SPY; - - /** - * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue - * to receive events from a stylus device within its touchable region. All other pointer - * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it. - * - * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is - * not set. - * - * The window must be a trusted overlay to use this input feature. - * - * @see #FLAG_NOT_TOUCHABLE * * @hide */ - public static final int INPUT_FEATURE_INTERCEPTS_STYLUS = - IInputConstants.InputFeature.INTERCEPTS_STYLUS; + @RequiresPermission(permission.MONITOR_INPUT) + public static final int INPUT_FEATURE_SPY = 1 << 2; /** * An internal annotation for flags that can be specified to {@link #inputFeatures}. * + * NOTE: These are not the same as {@link android.os.InputConfig} flags. + * * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "INPUT_FEATURE_" }, value = { - INPUT_FEATURE_NO_INPUT_CHANNEL, - INPUT_FEATURE_DISABLE_USER_ACTIVITY, - INPUT_FEATURE_SPY, - INPUT_FEATURE_INTERCEPTS_STYLUS, + @IntDef(flag = true, prefix = {"INPUT_FEATURE_"}, value = { + INPUT_FEATURE_NO_INPUT_CHANNEL, + INPUT_FEATURE_DISABLE_USER_ACTIVITY, + INPUT_FEATURE_SPY, }) - public @interface InputFeatureFlags {} + public @interface InputFeatureFlags { + } /** - * Control special features of the input subsystem. + * Control a set of features of the input subsystem that are exposed to the app process. + * + * WARNING: Do NOT use {@link android.os.InputConfig} flags! This must be set to flag values + * included in {@link InputFeatureFlags}. * - * @see #INPUT_FEATURE_NO_INPUT_CHANNEL - * @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY - * @see #INPUT_FEATURE_SPY - * @see #INPUT_FEATURE_INTERCEPTS_STYLUS * @hide + * @see InputFeatureFlags */ @InputFeatureFlags @UnsupportedAppUsage @@ -4845,10 +4828,6 @@ public interface WindowManager extends ViewManager { inputFeatures &= ~INPUT_FEATURE_SPY; features.add("INPUT_FEATURE_SPY"); } - if ((inputFeatures & INPUT_FEATURE_INTERCEPTS_STYLUS) != 0) { - inputFeatures &= ~INPUT_FEATURE_INTERCEPTS_STYLUS; - features.add("INPUT_FEATURE_INTERCEPTS_STYLUS"); - } if (inputFeatures != 0) { features.add(Integer.toHexString(inputFeatures)); } diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index f453d1f06e22c..db92310f2a261 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -63,16 +64,11 @@ static struct { jfieldID surfaceInset; jfieldID scaleFactor; jfieldID touchableRegion; - jfieldID visible; - jfieldID focusable; - jfieldID hasWallpaper; - jfieldID paused; - jfieldID trustedOverlay; jfieldID touchOcclusionMode; jfieldID ownerPid; jfieldID ownerUid; jfieldID packageName; - jfieldID inputFeatures; + jfieldID inputConfig; jfieldID displayId; jfieldID replaceTouchableRegionWithCrop; WeakRefHandleField touchableRegionSurfaceControl; @@ -162,64 +158,8 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.layoutParamsFlags = flags; mInfo.layoutParamsType = type; - using InputConfig = gui::WindowInfo::InputConfig; - // Determine the value for each of the InputConfig flags. We rely on a switch statement and - // -Wswitch-enum to give us a build error if we forget to explicitly handle an InputConfig flag. - mInfo.inputConfig = InputConfig::NONE; - InputConfig enumerationStart = InputConfig::NONE; - switch (enumerationStart) { - case InputConfig::NONE: - FALLTHROUGH_INTENDED; - case InputConfig::NOT_VISIBLE: - if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.visible) == JNI_FALSE) { - mInfo.inputConfig |= InputConfig::NOT_VISIBLE; - } - FALLTHROUGH_INTENDED; - case InputConfig::NOT_FOCUSABLE: - if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable) == JNI_FALSE) { - mInfo.inputConfig |= InputConfig::NOT_FOCUSABLE; - } - FALLTHROUGH_INTENDED; - case InputConfig::NOT_TOUCHABLE: - if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { - mInfo.inputConfig |= InputConfig::NOT_TOUCHABLE; - } - FALLTHROUGH_INTENDED; - case InputConfig::PREVENT_SPLITTING: - if (!flags.test(WindowInfo::Flag::SPLIT_TOUCH)) { - mInfo.inputConfig |= InputConfig::PREVENT_SPLITTING; - } - FALLTHROUGH_INTENDED; - case InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER: - if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.hasWallpaper) == JNI_TRUE) { - mInfo.inputConfig |= InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER; - } - FALLTHROUGH_INTENDED; - case InputConfig::IS_WALLPAPER: - if (type == WindowInfo::Type::WALLPAPER) { - mInfo.inputConfig |= InputConfig::IS_WALLPAPER; - } - FALLTHROUGH_INTENDED; - case InputConfig::PAUSE_DISPATCHING: - if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused) == JNI_TRUE) { - mInfo.inputConfig |= InputConfig::PAUSE_DISPATCHING; - } - FALLTHROUGH_INTENDED; - case InputConfig::TRUSTED_OVERLAY: - if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay) == JNI_TRUE) { - mInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY; - } - FALLTHROUGH_INTENDED; - case InputConfig::WATCH_OUTSIDE_TOUCH: - if (flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) { - mInfo.inputConfig |= InputConfig::WATCH_OUTSIDE_TOUCH; - } - FALLTHROUGH_INTENDED; - case InputConfig::SLIPPERY: - if (flags.test(WindowInfo::Flag::SLIPPERY)) { - mInfo.inputConfig |= InputConfig::SLIPPERY; - } - } + mInfo.inputConfig = static_cast( + env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig)); mInfo.touchOcclusionMode = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode)); @@ -228,8 +168,6 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.ownerUid = env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid); mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, ""); - mInfo.inputFeatures = static_cast( - env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures)); mInfo.displayId = env->GetIntField(obj, gInputWindowHandleClassInfo.displayId); @@ -359,17 +297,6 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion, regionObj.get()); - using InputConfig = gui::WindowInfo::InputConfig; - env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible, - !windowInfo.inputConfig.test(InputConfig::NOT_VISIBLE)); - env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable, - !windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)); - env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper, - windowInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); - env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, - windowInfo.inputConfig.test(InputConfig::PAUSE_DISPATCHING)); - env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay, - windowInfo.inputConfig.test(InputConfig::TRUSTED_OVERLAY)); env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode, static_cast(windowInfo.touchOcclusionMode)); env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid); @@ -377,8 +304,11 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn ScopedLocalRef packageName(env, env->NewStringUTF(windowInfo.packageName.data())); env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName, packageName.get()); - env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures, - static_cast(windowInfo.inputFeatures.get())); + + const auto inputConfig = windowInfo.inputConfig.get(); + static_assert(sizeof(inputConfig) == sizeof(int32_t)); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputConfig, + static_cast(inputConfig)); float transformVals[9]; for (int i = 0; i < 9; i++) { @@ -481,19 +411,6 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz, "touchableRegion", "Landroid/graphics/Region;"); - GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz, - "visible", "Z"); - - GET_FIELD_ID(gInputWindowHandleClassInfo.focusable, clazz, "focusable", "Z"); - - GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz, - "hasWallpaper", "Z"); - - GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz, - "paused", "Z"); - - GET_FIELD_ID(gInputWindowHandleClassInfo.trustedOverlay, clazz, "trustedOverlay", "Z"); - GET_FIELD_ID(gInputWindowHandleClassInfo.touchOcclusionMode, clazz, "touchOcclusionMode", "I"); GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz, @@ -505,8 +422,7 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.packageName, clazz, "packageName", "Ljava/lang/String;"); - GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz, - "inputFeatures", "I"); + GET_FIELD_ID(gInputWindowHandleClassInfo.inputConfig, clazz, "inputConfig", "I"); GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz, "displayId", "I"); diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java index dbd3f3529208f..d238dae634adf 100644 --- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -19,6 +19,7 @@ package com.android.server.input; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import android.os.IBinder; +import android.os.InputConfig; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputMonitor; @@ -56,18 +57,13 @@ class GestureMonitorSpyWindow { mWindowHandle.name = name; mWindowHandle.token = mClientChannel.getToken(); mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; - mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mWindowHandle.visible = true; - mWindowHandle.focusable = false; - mWindowHandle.hasWallpaper = false; - mWindowHandle.paused = false; mWindowHandle.ownerPid = pid; mWindowHandle.ownerUid = uid; - mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY; mWindowHandle.scaleFactor = 1.0f; - mWindowHandle.trustedOverlay = true; mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); + mWindowHandle.inputConfig = + InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY; final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.setInputWindowInfo(mInputSurface, mWindowHandle); diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java index 3c454080ef1c2..1a19385e71c52 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java @@ -19,6 +19,7 @@ package com.android.server.inputmethod; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import android.annotation.NonNull; +import android.os.InputConfig; import android.os.Process; import android.view.InputApplicationHandle; import android.view.InputChannel; @@ -56,20 +57,17 @@ final class HandwritingEventReceiverSurface { mWindowHandle.name = name; mWindowHandle.token = mClientChannel.getToken(); mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; - mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mWindowHandle.visible = true; - mWindowHandle.focusable = false; - mWindowHandle.hasWallpaper = false; - mWindowHandle.paused = false; mWindowHandle.ownerPid = Process.myPid(); mWindowHandle.ownerUid = Process.myUid(); - mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY - | WindowManager.LayoutParams.INPUT_FEATURE_INTERCEPTS_STYLUS; mWindowHandle.scaleFactor = 1.0f; - mWindowHandle.trustedOverlay = true; mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); + mWindowHandle.inputConfig = + InputConfig.NOT_FOCUSABLE + | InputConfig.NOT_TOUCHABLE + | InputConfig.SPY + | InputConfig.INTERCEPTS_STYLUS + | InputConfig.TRUSTED_OVERLAY; final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.setInputWindowInfo(mInputSurface, mWindowHandle); @@ -85,7 +83,7 @@ final class HandwritingEventReceiverSurface { void startIntercepting(int imePid, int imeUid) { mWindowHandle.ownerPid = imePid; mWindowHandle.ownerUid = imeUid; - mWindowHandle.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_SPY; + mWindowHandle.inputConfig &= ~InputConfig.SPY; new SurfaceControl.Transaction() .setInputWindowInfo(mInputSurface, mWindowHandle) diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java index f9689a8a2bca7..d4648a4f313c9 100644 --- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java +++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java @@ -27,6 +27,7 @@ import android.graphics.RectF; import android.graphics.Region; import android.os.Handler; import android.os.IBinder; +import android.os.InputConfig; import android.os.Looper; import android.os.Message; import android.util.Slog; @@ -153,7 +154,8 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener { final List tempVisibleWindows = new ArrayList<>(); for (InputWindowHandle window : windowHandles) { - if (window.visible && window.getWindow() != null) { + final boolean visible = (window.inputConfig & InputConfig.NOT_VISIBLE) == 0; + if (visible && window.getWindow() != null) { tempVisibleWindows.add(window); } } @@ -641,7 +643,8 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener { final RecentsAnimationController controller = service.getRecentsAnimationController(); instance.mIgnoreDuetoRecentsAnimation = windowState != null && controller != null && controller.shouldIgnoreForAccessibility(windowState); - instance.mIsTrustedOverlay = inputWindowHandle.trustedOverlay; + instance.mIsTrustedOverlay = + (inputWindowHandle.inputConfig & InputConfig.TRUSTED_OVERLAY) != 0; // TODO (b/199358388) : gets the letterbox bounds of the window from other way. if (windowState != null && windowState.areAppWindowBoundsLetterboxed()) { diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java index 19d5449254ff4..8622bd32fc685 100644 --- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java +++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java @@ -19,6 +19,7 @@ package com.android.server.wm; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.os.IBinder; +import android.os.InputConfig; import android.os.InputConstants; import android.os.Looper; import android.os.Process; @@ -111,13 +112,12 @@ class ActivityRecordInputSink { mActivityRecord.getDisplayId()); inputWindowHandle.replaceTouchableRegionWithCrop = true; inputWindowHandle.name = mName; + inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; inputWindowHandle.ownerUid = Process.myUid(); inputWindowHandle.ownerPid = Process.myPid(); - inputWindowHandle.layoutParamsFlags = - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; inputWindowHandle.dispatchingTimeoutMillis = InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; + inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE; return inputWindowHandle; } @@ -169,5 +169,4 @@ class ActivityRecordInputSink { finishInputEvent(event, true); } } - } diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 00380bb6e84e1..c47d778c60bc3 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -44,6 +44,7 @@ import android.hardware.input.InputManager; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.os.InputConfig; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -127,7 +128,7 @@ class DragState { @Nullable private ValueAnimator mAnimator; private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f); - private Point mDisplaySize = new Point(); + private final Point mDisplaySize = new Point(); // A surface used to catch input events for the drag-and-drop operation. SurfaceControl mInputSurface; @@ -160,8 +161,7 @@ class DragState { private void showInputSurface() { if (mInputSurface == null) { - mInputSurface = mService.makeSurfaceBuilder( - mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession()) + mInputSurface = mService.makeSurfaceBuilder(mDisplayContent.getSession()) .setContainerLayer() .setName("Drag and Drop Input Consumer") .setCallsite("DragState.showInputSurface") @@ -174,17 +174,18 @@ class DragState { return; } - mTransaction.show(mInputSurface); - mTransaction.setInputWindowInfo(mInputSurface, h); - mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE); - + // Crop the input surface to the display size. mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); - mTransaction.setWindowCrop(mInputSurface, mTmpClipRect); + + mTransaction.show(mInputSurface) + .setInputWindowInfo(mInputSurface, h) + .setLayer(mInputSurface, Integer.MAX_VALUE) + .setCrop(mInputSurface, mTmpClipRect); // syncInputWindows here to ensure the input window info is sent before the // transferTouchFocus is called. - mTransaction.syncInputWindows(); - mTransaction.apply(true); + mTransaction.syncInputWindows() + .apply(true /*sync*/); } /** @@ -361,29 +362,20 @@ class DragState { display.getDisplayId()); mDragWindowHandle.name = "drag"; mDragWindowHandle.token = mClientChannel.getToken(); - mDragWindowHandle.layoutParamsFlags = 0; mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mDragWindowHandle.visible = true; - // Allows the system to consume keys when dragging is active. This can also be used to - // modify the drag state on key press. Example, cancel drag on escape key. - mDragWindowHandle.focusable = true; - mDragWindowHandle.hasWallpaper = false; - mDragWindowHandle.paused = false; mDragWindowHandle.ownerPid = Process.myPid(); mDragWindowHandle.ownerUid = Process.myUid(); - mDragWindowHandle.inputFeatures = 0; mDragWindowHandle.scaleFactor = 1.0f; + // Keep the default behavior of this window to be focusable, which allows the system + // to consume keys when dragging is active. This can also be used to modify the drag + // state on key press. For example, cancel drag on escape key. + mDragWindowHandle.inputConfig = InputConfig.PREVENT_SPLITTING; + // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); - // The drag window covers the entire display - mDragWindowHandle.frameLeft = 0; - mDragWindowHandle.frameTop = 0; - mDragWindowHandle.frameRight = mDisplaySize.x; - mDragWindowHandle.frameBottom = mDisplaySize.y; - // Pause rotations before a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during drag"); mService.mRoot.forAllDisplays(dc -> { diff --git a/services/core/java/com/android/server/wm/InputConfigAdapter.java b/services/core/java/com/android/server/wm/InputConfigAdapter.java new file mode 100644 index 0000000000000..2dcde4ee2ba8a --- /dev/null +++ b/services/core/java/com/android/server/wm/InputConfigAdapter.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2022 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.os.InputConfig; +import android.view.InputWindowHandle.InputConfigFlags; +import android.view.WindowManager.LayoutParams; + +import java.util.List; + +/** + * A helper to determine the {@link InputConfigFlags} that control the behavior of an input window + * from several WM attributes. + */ +class InputConfigAdapter { + private InputConfigAdapter() {} + + /** Describes a mapping from a flag value to a {@link InputConfigFlags} value. */ + private static class FlagMapping { + final int mFlag; + final int mInputConfig; + final boolean mInverted; + + FlagMapping(int flag, int inputConfig, boolean inverted) { + mFlag = flag; + mInputConfig = inputConfig; + mInverted = inverted; + } + } + + /** + * A mapping from {@link LayoutParams.InputFeatureFlags} to {@link InputConfigFlags} for + * input configurations that can be mapped directly from a corresponding LayoutParams input + * feature. + */ + private static final List INPUT_FEATURE_TO_CONFIG_MAP = List.of( + new FlagMapping( + LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL, + InputConfig.NO_INPUT_CHANNEL, false /* inverted */), + new FlagMapping( + LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY, + InputConfig.DISABLE_USER_ACTIVITY, false /* inverted */), + new FlagMapping( + LayoutParams.INPUT_FEATURE_SPY, + InputConfig.SPY, false /* inverted */)); + + @InputConfigFlags + private static final int INPUT_FEATURE_TO_CONFIG_MASK = + computeMask(INPUT_FEATURE_TO_CONFIG_MAP); + + /** + * A mapping from {@link LayoutParams.Flags} to {@link InputConfigFlags} for input + * configurations that can be mapped directly from a corresponding LayoutParams flag. + * + * NOTE: The layout params flag {@link LayoutParams#FLAG_NOT_FOCUSABLE} is not handled by this + * adapter, and must be handled explicitly. + */ + private static final List LAYOUT_PARAM_FLAG_TO_CONFIG_MAP = List.of( + new FlagMapping( + LayoutParams.FLAG_NOT_TOUCHABLE, + InputConfig.NOT_TOUCHABLE, false /* inverted */), + new FlagMapping( + LayoutParams.FLAG_SPLIT_TOUCH, + InputConfig.PREVENT_SPLITTING, true /* inverted */), + new FlagMapping( + LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, + InputConfig.WATCH_OUTSIDE_TOUCH, false /* inverted */), + new FlagMapping( + LayoutParams.FLAG_SLIPPERY, + InputConfig.SLIPPERY, false /* inverted */)); + + @InputConfigFlags + private static final int LAYOUT_PARAM_FLAG_TO_CONFIG_MASK = + computeMask(LAYOUT_PARAM_FLAG_TO_CONFIG_MAP); + + /** + * Returns a mask of all the input config flags configured by + * {@link #getInputConfigFromWindowParams(int, int, int)}. + */ + @InputConfigFlags + static int getMask() { + return LAYOUT_PARAM_FLAG_TO_CONFIG_MASK | INPUT_FEATURE_TO_CONFIG_MASK + | InputConfig.IS_WALLPAPER; + } + + /** + * Get the {@link InputConfigFlags} value that provides the input window behavior specified by + * the given WindowManager attributes. + * + * Use {@link #getMask()} to get the mask of all the input config flags set by this method. + * + * @param type the window type + * @param flags the window flags + * @param inputFeatures the input feature flags + */ + @InputConfigFlags + static int getInputConfigFromWindowParams(@LayoutParams.WindowType int type, + @LayoutParams.Flags int flags, @LayoutParams.InputFeatureFlags int inputFeatures) { + return (type == LayoutParams.TYPE_WALLPAPER ? InputConfig.IS_WALLPAPER : 0) + | applyMapping(flags, LAYOUT_PARAM_FLAG_TO_CONFIG_MAP) + | applyMapping(inputFeatures, INPUT_FEATURE_TO_CONFIG_MAP); + } + + @InputConfigFlags + private static int applyMapping(int flags, List flagToConfigMap) { + int inputConfig = 0; + for (final FlagMapping mapping : flagToConfigMap) { + final boolean flagSet = (flags & mapping.mFlag) != 0; + if (flagSet != mapping.mInverted) { + inputConfig |= mapping.mInputConfig; + } + } + return inputConfig; + } + + @InputConfigFlags + private static int computeMask(List flagToConfigMap) { + int mask = 0; + for (final FlagMapping mapping : flagToConfigMap) { + mask |= mapping.mInputConfig; + } + return mask; + } +} diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index cbd5646968d76..59be3e05f2c05 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -22,6 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; +import android.os.InputConfig; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -70,19 +71,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mWindowHandle.name = name; mWindowHandle.token = mClientChannel.getToken(); mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; - mWindowHandle.layoutParamsFlags = 0; mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mWindowHandle.visible = true; - mWindowHandle.focusable = false; - mWindowHandle.hasWallpaper = false; - mWindowHandle.paused = false; mWindowHandle.ownerPid = Process.myPid(); mWindowHandle.ownerUid = Process.myUid(); - mWindowHandle.inputFeatures = 0; mWindowHandle.scaleFactor = 1.0f; - mWindowHandle.trustedOverlay = true; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY; - mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId).getSession()) + mInputSurface = mService.makeSurfaceBuilder( + mService.mRoot.getDisplayContent(displayId).getSession()) .setContainerLayer() .setName("Input Consumer " + name) .setCallsite("InputConsumerImpl") diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index c4f685b690618..8038f4404799a 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -21,7 +21,6 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; @@ -53,6 +52,7 @@ import android.annotation.Nullable; import android.graphics.Region; import android.os.Handler; import android.os.IBinder; +import android.os.InputConfig; import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; @@ -61,6 +61,7 @@ import android.util.Slog; import android.view.InputChannel; import android.view.InputWindowHandle; import android.view.SurfaceControl; +import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; @@ -221,15 +222,13 @@ final class InputMonitor { inputChannel, clientPid, clientUser, mDisplayId); switch (name) { case INPUT_CONSUMER_WALLPAPER: - consumer.mWindowHandle.hasWallpaper = true; + consumer.mWindowHandle.inputConfig |= InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER; break; case INPUT_CONSUMER_PIP: - // The touchable region of the Pip input window is cropped to the bounds of the - // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through - consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL; + // This is a valid consumer type, but we don't need any additional configurations. break; case INPUT_CONSUMER_RECENTS_ANIMATION: - consumer.mWindowHandle.focusable = true; + consumer.mWindowHandle.inputConfig &= ~InputConfig.NOT_FOCUSABLE; break; default: throw new IllegalArgumentException("Illegal input consumer : " + name @@ -247,11 +246,24 @@ final class InputMonitor { inputWindowHandle.setToken(w.mInputChannelToken); inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis()); inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode()); - inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures); inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused); - inputWindowHandle.setVisible(w.isVisible()); inputWindowHandle.setWindowToken(w.mClient); + // Update layout params flags to force the window to be not touch modal. We do this to + // restrict the window's touchable region to the task even if it requests touches outside + // its window bounds. An example is a dialog in primary split should get touches outside its + // window within the primary task but should not get any touches going to the secondary + // task. + int flags = w.mAttrs.flags; + if (w.mAttrs.isModal()) { + flags = flags | FLAG_NOT_TOUCH_MODAL; + } + inputWindowHandle.setLayoutParamsFlags(flags); + inputWindowHandle.setInputConfigMasked( + InputConfigAdapter.getInputConfigFromWindowParams( + w.mAttrs.type, flags, w.mAttrs.inputFeatures), + InputConfigAdapter.getMask()); + final boolean focusable = w.canReceiveKeys() && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop()); inputWindowHandle.setFocusable(focusable); @@ -270,17 +282,6 @@ final class InputMonitor { // what is on screen to what is actually being touched in the UI. inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f); - // Update layout params flags to force the window to be not touch modal. We do this to - // restrict the window's touchable region to the task even if it request touches outside its - // window bounds. An example is a dialog in primary split should get touches outside its - // window within the primary task but should not get any touches going to the secondary - // task. - int flags = w.mAttrs.flags; - if (w.mAttrs.isModal()) { - flags = flags | FLAG_NOT_TOUCH_MODAL; - } - inputWindowHandle.setLayoutParamsFlags(flags); - boolean useSurfaceBoundsAsTouchRegion = false; SurfaceControl touchableRegionCrop = null; final Task task = w.getTask(); @@ -590,6 +591,8 @@ final class InputMonitor { if (mAddWallpaperInputConsumerHandle) { if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) { + mWallpaperInputConsumer.mWindowHandle + .replaceTouchableRegionWithCrop(null /* use this surface's bounds */); // Add the wallpaper input consumer above the first visible wallpaper. mWallpaperInputConsumer.show(mInputTransaction, w); mAddWallpaperInputConsumerHandle = false; @@ -631,24 +634,27 @@ final class InputMonitor { static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, WindowState w) { - populateOverlayInputInfo(inputWindowHandle, w.isVisible()); + populateOverlayInputInfo(inputWindowHandle); inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode()); } // This would reset InputWindowHandle fields to prevent it could be found by input event. // We need to check if any new field of InputWindowHandle could impact the result. @VisibleForTesting - static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, - boolean isVisible) { + static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle) { inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input. - inputWindowHandle.setVisible(isVisible); inputWindowHandle.setFocusable(false); - inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL); // The input window handle without input channel must not have a token. inputWindowHandle.setToken(null); inputWindowHandle.setScaleFactor(1f); - inputWindowHandle.setLayoutParamsFlags( - FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE); + final int defaultType = WindowManager.LayoutParams.TYPE_APPLICATION; + inputWindowHandle.setLayoutParamsType(defaultType); + inputWindowHandle.setInputConfigMasked( + InputConfigAdapter.getInputConfigFromWindowParams( + defaultType, + FLAG_NOT_TOUCHABLE, + INPUT_FEATURE_NO_INPUT_CHANNEL), + InputConfigAdapter.getMask()); inputWindowHandle.clearTouchableRegion(); inputWindowHandle.setTouchableRegionCrop(null); } @@ -666,7 +672,7 @@ final class InputMonitor { inputWindowHandle.setName(name); inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY); inputWindowHandle.setTrustedOverlay(true); - populateOverlayInputInfo(inputWindowHandle, true /* isVisible */); + populateOverlayInputInfo(inputWindowHandle); setInputWindowInfoIfNeeded(t, sc, inputWindowHandle); } diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java index 142d2933f0467..301c1846249ff 100644 --- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java +++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java @@ -20,10 +20,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Region; import android.os.IBinder; +import android.os.InputConfig; import android.view.IWindow; import android.view.InputApplicationHandle; import android.view.InputWindowHandle; +import android.view.InputWindowHandle.InputConfigFlags; import android.view.SurfaceControl; +import android.view.WindowManager; import java.util.Objects; @@ -31,8 +34,10 @@ import java.util.Objects; * The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary * updates to surface, e.g. if there are no changes, then skip invocation of * {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}. + * It also sets the {@link InputConfigFlags} values for the input window. */ class InputWindowHandleWrapper { + /** The wrapped handle should not be directly exposed to avoid untracked changes. */ private final @NonNull InputWindowHandle mHandle; @@ -65,7 +70,20 @@ class InputWindowHandleWrapper { } boolean isFocusable() { - return mHandle.focusable; + return (mHandle.inputConfig & InputConfig.NOT_FOCUSABLE) == 0; + } + + boolean isPaused() { + return (mHandle.inputConfig & InputConfig.PAUSE_DISPATCHING) != 0; + } + + boolean isTrustedOverlay() { + return (mHandle.inputConfig & InputConfig.TRUSTED_OVERLAY) != 0; + } + + boolean hasWallpaper() { + return (mHandle.inputConfig & InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER) + != 0; } InputApplicationHandle getInputApplicationHandle() { @@ -96,7 +114,7 @@ class InputWindowHandleWrapper { mChanged = true; } - void setLayoutParamsFlags(int flags) { + void setLayoutParamsFlags(@WindowManager.LayoutParams.Flags int flags) { if (mHandle.layoutParamsFlags == flags) { return; } @@ -136,19 +154,11 @@ class InputWindowHandleWrapper { mChanged = true; } - void setVisible(boolean visible) { - if (mHandle.visible == visible) { - return; - } - mHandle.visible = visible; - mChanged = true; - } - void setFocusable(boolean focusable) { - if (mHandle.focusable == focusable) { + if (isFocusable() == focusable) { return; } - mHandle.focusable = focusable; + mHandle.setInputConfig(InputConfig.NOT_FOCUSABLE, !focusable); mChanged = true; } @@ -161,26 +171,27 @@ class InputWindowHandleWrapper { } void setHasWallpaper(boolean hasWallpaper) { - if (mHandle.hasWallpaper == hasWallpaper) { + if (this.hasWallpaper() == hasWallpaper) { return; } - mHandle.hasWallpaper = hasWallpaper; + mHandle.setInputConfig(InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER, + hasWallpaper); mChanged = true; } void setPaused(boolean paused) { - if (mHandle.paused == paused) { + if (isPaused() == paused) { return; } - mHandle.paused = paused; + mHandle.setInputConfig(InputConfig.PAUSE_DISPATCHING, paused); mChanged = true; } void setTrustedOverlay(boolean trustedOverlay) { - if (mHandle.trustedOverlay == trustedOverlay) { + if (isTrustedOverlay() == trustedOverlay) { return; } - mHandle.trustedOverlay = trustedOverlay; + mHandle.setInputConfig(InputConfig.TRUSTED_OVERLAY, trustedOverlay); mChanged = true; } @@ -208,14 +219,6 @@ class InputWindowHandleWrapper { mChanged = true; } - void setInputFeatures(int features) { - if (mHandle.inputFeatures == features) { - return; - } - mHandle.inputFeatures = features; - mChanged = true; - } - void setDisplayId(int displayId) { if (mHandle.displayId == displayId) { return; @@ -276,8 +279,14 @@ class InputWindowHandleWrapper { mChanged = true; } - boolean isTrustedOverlay() { - return mHandle.trustedOverlay; + void setInputConfigMasked(@InputConfigFlags int inputConfig, @InputConfigFlags int mask) { + final int inputConfigMasked = inputConfig & mask; + if (inputConfigMasked == (mHandle.inputConfig & mask)) { + return; + } + mHandle.inputConfig &= ~mask; + mHandle.inputConfig |= inputConfigMasked; + mChanged = true; } @Override diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 4b98013a99cc1..40df02c176e59 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -24,6 +24,7 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; +import android.os.InputConfig; import android.os.Process; import android.view.GestureDetector; import android.view.InputChannel; @@ -290,16 +291,12 @@ public class Letterbox { win.getDisplayId()); mWindowHandle.name = name; mWindowHandle.token = mToken; - mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH - | WindowManager.LayoutParams.FLAG_SLIPPERY; mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mWindowHandle.visible = true; mWindowHandle.ownerPid = Process.myPid(); mWindowHandle.ownerUid = Process.myUid(); mWindowHandle.scaleFactor = 1.0f; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SLIPPERY; } void updateTouchableRegion(Rect frame) { diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 348cfb62582eb..47c397d12720a 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -40,6 +40,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; +import android.os.InputConfig; import android.os.Process; import android.os.RemoteException; import android.os.Trace; @@ -219,30 +220,17 @@ class TaskPositioner implements IBinder.DeathRecipient { displayContent.getDisplayId()); mDragWindowHandle.name = TAG; mDragWindowHandle.token = mClientChannel.getToken(); - mDragWindowHandle.layoutParamsFlags = 0; mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - mDragWindowHandle.visible = true; - // When dragging the window around, we do not want to steal focus for the window. - mDragWindowHandle.focusable = false; - mDragWindowHandle.hasWallpaper = false; - mDragWindowHandle.paused = false; mDragWindowHandle.ownerPid = Process.myPid(); mDragWindowHandle.ownerUid = Process.myUid(); - mDragWindowHandle.inputFeatures = 0; mDragWindowHandle.scaleFactor = 1.0f; + // When dragging the window around, we do not want to steal focus for the window. + mDragWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE; // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); - // The drag window covers the entire display. - final Rect displayBounds = mTmpRect; - displayContent.getBounds(mTmpRect); - mDragWindowHandle.frameLeft = displayBounds.left; - mDragWindowHandle.frameTop = displayBounds.top; - mDragWindowHandle.frameRight = displayBounds.right; - mDragWindowHandle.frameBottom = displayBounds.bottom; - // Pause rotations before a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position"); mDisplayContent.getDisplayRotation().pause(); @@ -250,6 +238,8 @@ class TaskPositioner implements IBinder.DeathRecipient { // Notify InputMonitor to take mDragWindowHandle. mService.mTaskPositioningController.showInputSurface(win.getDisplayId()); + final Rect displayBounds = mTmpRect; + displayContent.getBounds(displayBounds); final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics); diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 8f24f2615fac0..68bf2b2424e72 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -83,17 +83,18 @@ class TaskPositioningController { return; } - mTransaction.show(mInputSurface); - mTransaction.setInputWindowInfo(mInputSurface, h); - mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE); - final Display display = dc.getDisplay(); final Point p = new Point(); display.getRealSize(p); - mTmpClipRect.set(0, 0, p.x, p.y); - mTransaction.setWindowCrop(mInputSurface, mTmpClipRect); - mTransaction.syncInputWindows().apply(); + + mTransaction.show(mInputSurface) + .setInputWindowInfo(mInputSurface, h) + .setLayer(mInputSurface, Integer.MAX_VALUE) + .setPosition(mInputSurface, 0, 0) + .setCrop(mInputSurface, mTmpClipRect) + .syncInputWindows() + .apply(); } boolean startMovingTask(IWindow window, float startX, float startY) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2cff030892347..49d9b65dde686 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -192,6 +192,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.IRemoteCallback; +import android.os.InputConfig; import android.os.Looper; import android.os.Message; import android.os.Parcel; @@ -8452,43 +8453,48 @@ public class WindowManagerService extends IWindowManager.Stub } private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid, - int displayId, SurfaceControl surface, String name, - InputApplicationHandle applicationHandle, int flags, - int privateFlags, int type, Region region, IWindow window) { - InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId); + int displayId, SurfaceControl surface, String name, + InputApplicationHandle applicationHandle, int flags, + int privateFlags, int type, Region region, IWindow window) { + final InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId); h.token = channelToken; h.setWindowToken(window); h.name = name; flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid); - final int sanitizedFlags = flags & (FLAG_NOT_TOUCHABLE - | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE); - h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags; + final int sanitizedLpFlags = + (flags & (FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE)) + | LayoutParams.FLAG_NOT_TOUCH_MODAL; h.layoutParamsType = type; - h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; - h.focusable = (flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0; - h.hasWallpaper = false; - h.paused = false; - - h.ownerUid = callingUid; - h.ownerPid = callingPid; + h.layoutParamsFlags = sanitizedLpFlags; // Do not allow any input features to be set without sanitizing them first. - h.inputFeatures = 0; + h.inputConfig = InputConfigAdapter.getInputConfigFromWindowParams( + type, sanitizedLpFlags, 0 /*inputFeatures*/); - if (region == null) { - h.replaceTouchableRegionWithCrop(null); - } else { - h.touchableRegion.set(region); - h.replaceTouchableRegionWithCrop = false; - h.setTouchableRegionCrop(surface); + + if ((flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0) { + h.inputConfig |= InputConfig.NOT_FOCUSABLE; } // Check private trusted overlay flag to set trustedOverlay field of input window handle. - h.trustedOverlay = (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0; + if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { + h.inputConfig |= InputConfig.TRUSTED_OVERLAY; + } - SurfaceControl.Transaction t = mTransactionFactory.get(); + h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; + h.ownerUid = callingUid; + h.ownerPid = callingPid; + + if (region == null) { + h.replaceTouchableRegionWithCrop = true; + } else { + h.touchableRegion.set(region); + } + h.setTouchableRegionCrop(null /* use the input surface's bounds */); + + final SurfaceControl.Transaction t = mTransactionFactory.get(); t.setInputWindowInfo(surface, h); t.apply(); t.close(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 8ee6feb26a53e..3dad2ba40627e 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1190,6 +1190,7 @@ class WindowState extends WindowContainer implements WindowManagerP mActivityRecord != null ? mActivityRecord.getInputApplicationHandle(false /* update */) : null, getDisplayId())); + mInputWindowHandle.setFocusable(false); mInputWindowHandle.setOwnerPid(s.mPid); mInputWindowHandle.setOwnerUid(s.mUid); mInputWindowHandle.setName(getName()); diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index 46ef7ed092dee..5ea8fd373f0b0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Matrix; @@ -134,6 +135,12 @@ public class StubTransaction extends SurfaceControl.Transaction { return this; } + @Override + @NonNull + public SurfaceControl.Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) { + return this; + } + @Override public SurfaceControl.Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) { return this; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index e70dd08af8a14..e4f691b338e12 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -29,6 +29,8 @@ import static android.view.Surface.ROTATION_90; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; +import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; @@ -81,6 +83,7 @@ import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; +import android.os.InputConfig; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; @@ -754,10 +757,15 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(win0.canReceiveTouchInput()); } + private boolean testFlag(int flags, int test) { + return (flags & test) == test; + } + @Test public void testUpdateInputWindowHandle() { final WindowState win = createWindow(null, TYPE_APPLICATION, "win"); win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; + win.mAttrs.flags = FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH; final InputWindowHandle handle = new InputWindowHandle( win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId()); final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle); @@ -767,13 +775,14 @@ public class WindowStateTests extends WindowTestsBase { mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win); assertTrue(handleWrapper.isChanged()); + assertTrue(testFlag(handle.inputConfig, InputConfig.WATCH_OUTSIDE_TOUCH)); + assertFalse(testFlag(handle.inputConfig, InputConfig.PREVENT_SPLITTING)); + assertTrue(testFlag(handle.inputConfig, InputConfig.DISABLE_USER_ACTIVITY)); // The window of standard resizable task should not use surface crop as touchable region. assertFalse(handle.replaceTouchableRegionWithCrop); assertEquals(inputChannelToken, handle.token); assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */), handle.inputApplicationHandle); - assertEquals(win.mAttrs.inputFeatures, handle.inputFeatures); - assertEquals(win.isVisible(), handle.visible); final SurfaceControl sc = mock(SurfaceControl.class); final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction; @@ -799,15 +808,13 @@ public class WindowStateTests extends WindowTestsBase { assertEquals(rotatedBounds, handle.touchableRegion.getBounds()); // Populate as an overlay to disable the input of window. - InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */); + InputMonitor.populateOverlayInputInfo(handleWrapper); // The overlay attributes should be set. assertTrue(handleWrapper.isChanged()); - assertFalse(handle.focusable); - assertFalse(handle.visible); + assertFalse(handleWrapper.isFocusable()); assertNull(handle.token); assertEquals(0L, handle.dispatchingTimeoutMillis); - assertEquals(WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL, - handle.inputFeatures); + assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL)); } @Test