Merge changes from topic "merge-input-config-feature-tm" into tm-dev

* changes:
  Use InputConfig flags in InputWindowHandle API
  WindowInfo: Merge InputConfig and Feature flags
This commit is contained in:
TreeHugger Robot
2022-03-05 03:53:59 +00:00
committed by Android (Google) Code Review
19 changed files with 409 additions and 333 deletions

View File

@@ -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<SurfaceControl> 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;
}
}

View File

@@ -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));
}

View File

@@ -23,6 +23,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <binder/IPCThreadState.h>
#include <ftl/cast.h>
#include <gui/SurfaceControl.h>
#include <gui/WindowInfo.h>
#include <nativehelper/JNIHelp.h>
@@ -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<gui::WindowInfo::InputConfig>(
env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig));
mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
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, "<null>");
mInfo.inputFeatures = static_cast<WindowInfo::Feature>(
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<int32_t>(windowInfo.touchOcclusionMode));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
@@ -377,8 +304,11 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
ScopedLocalRef<jstring> packageName(env, env->NewStringUTF(windowInfo.packageName.data()));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
packageName.get());
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures,
static_cast<int32_t>(windowInfo.inputFeatures.get()));
const auto inputConfig = windowInfo.inputConfig.get();
static_assert(sizeof(inputConfig) == sizeof(int32_t));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputConfig,
static_cast<int32_t>(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");

View File

@@ -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);

View File

@@ -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)

View File

@@ -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<InputWindowHandle> 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()) {

View File

@@ -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);
}
}
}

View File

@@ -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 -> {

View File

@@ -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<FlagMapping> 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<FlagMapping> 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<FlagMapping> 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<FlagMapping> flagToConfigMap) {
int mask = 0;
for (final FlagMapping mapping : flagToConfigMap) {
mask |= mapping.mInputConfig;
}
return mask;
}
}

View File

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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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();

View File

@@ -1190,6 +1190,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mActivityRecord != null
? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
getDisplayId()));
mInputWindowHandle.setFocusable(false);
mInputWindowHandle.setOwnerPid(s.mPid);
mInputWindowHandle.setOwnerUid(s.mUid);
mInputWindowHandle.setName(getName());

View File

@@ -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;

View File

@@ -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