Merge "Ensure handwriting session can only be started from inside app bounds" into tm-dev am: a4f617f451
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17071330 Change-Id: Id5821cce58edce608a9eb8d38d8001c2196d4b30 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -164,6 +164,38 @@ public final class InputWindowHandle {
|
||||
this.displayId = displayId;
|
||||
}
|
||||
|
||||
public InputWindowHandle(InputWindowHandle other) {
|
||||
// Do not copy ptr to prevent this copy from sharing the same native object.
|
||||
ptr = 0;
|
||||
inputApplicationHandle = new InputApplicationHandle(other.inputApplicationHandle);
|
||||
token = other.token;
|
||||
windowToken = other.windowToken;
|
||||
window = other.window;
|
||||
name = other.name;
|
||||
layoutParamsFlags = other.layoutParamsFlags;
|
||||
layoutParamsType = other.layoutParamsType;
|
||||
dispatchingTimeoutMillis = other.dispatchingTimeoutMillis;
|
||||
frameLeft = other.frameLeft;
|
||||
frameTop = other.frameTop;
|
||||
frameRight = other.frameRight;
|
||||
frameBottom = other.frameBottom;
|
||||
surfaceInset = other.surfaceInset;
|
||||
scaleFactor = other.scaleFactor;
|
||||
touchableRegion.set(other.touchableRegion);
|
||||
inputConfig = other.inputConfig;
|
||||
touchOcclusionMode = other.touchOcclusionMode;
|
||||
ownerPid = other.ownerPid;
|
||||
ownerUid = other.ownerUid;
|
||||
packageName = other.packageName;
|
||||
displayId = other.displayId;
|
||||
touchableRegionSurfaceControl = other.touchableRegionSurfaceControl;
|
||||
replaceTouchableRegionWithCrop = other.replaceTouchableRegionWithCrop;
|
||||
if (other.transform != null) {
|
||||
transform = new Matrix();
|
||||
transform.set(other.transform);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(name != null ? name : "")
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.view.InputWindowHandle;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
|
||||
|
||||
final class HandwritingEventReceiverSurface {
|
||||
|
||||
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
|
||||
@@ -39,7 +38,6 @@ final class HandwritingEventReceiverSurface {
|
||||
// TODO(b/217538817): Specify the ordering in WM by usage.
|
||||
private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
|
||||
|
||||
private final InputApplicationHandle mApplicationHandle;
|
||||
private final InputWindowHandle mWindowHandle;
|
||||
private final InputChannel mClientChannel;
|
||||
private final SurfaceControl mInputSurface;
|
||||
@@ -47,13 +45,11 @@ final class HandwritingEventReceiverSurface {
|
||||
|
||||
HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
|
||||
@NonNull InputChannel inputChannel) {
|
||||
mApplicationHandle = new InputApplicationHandle(null, name,
|
||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
|
||||
|
||||
mClientChannel = inputChannel;
|
||||
mInputSurface = sc;
|
||||
|
||||
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
|
||||
mWindowHandle = new InputWindowHandle(new InputApplicationHandle(null, name,
|
||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS), displayId);
|
||||
mWindowHandle.name = name;
|
||||
mWindowHandle.token = mClientChannel.getToken();
|
||||
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
|
||||
@@ -61,7 +57,6 @@ final class HandwritingEventReceiverSurface {
|
||||
mWindowHandle.ownerPid = Process.myPid();
|
||||
mWindowHandle.ownerUid = Process.myUid();
|
||||
mWindowHandle.scaleFactor = 1.0f;
|
||||
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
|
||||
mWindowHandle.inputConfig =
|
||||
InputConfig.NOT_FOCUSABLE
|
||||
| InputConfig.NOT_TOUCHABLE
|
||||
@@ -69,6 +64,7 @@ final class HandwritingEventReceiverSurface {
|
||||
| InputConfig.INTERCEPTS_STYLUS
|
||||
| InputConfig.TRUSTED_OVERLAY;
|
||||
|
||||
// The touchable region of this input surface is not initially configured.
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
t.setInputWindowInfo(mInputSurface, mWindowHandle);
|
||||
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
|
||||
@@ -85,6 +81,10 @@ final class HandwritingEventReceiverSurface {
|
||||
mWindowHandle.ownerUid = imeUid;
|
||||
mWindowHandle.inputConfig &= ~InputConfig.SPY;
|
||||
|
||||
// Update the touchable region so that the IME can intercept stylus events
|
||||
// across the entire display.
|
||||
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
|
||||
|
||||
new SurfaceControl.Transaction()
|
||||
.setInputWindowInfo(mInputSurface, mWindowHandle)
|
||||
.apply();
|
||||
@@ -108,4 +108,8 @@ final class HandwritingEventReceiverSurface {
|
||||
SurfaceControl getSurface() {
|
||||
return mInputSurface;
|
||||
}
|
||||
|
||||
InputWindowHandle getInputWindowHandle() {
|
||||
return mWindowHandle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.AnyThread;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UiThread;
|
||||
import android.hardware.input.InputManagerInternal;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.util.Slog;
|
||||
import android.view.BatchedInputEventReceiver;
|
||||
@@ -90,7 +91,7 @@ final class HandwritingModeController {
|
||||
* InputEventReceiver that batches events according to the current thread's Choreographer.
|
||||
*/
|
||||
@UiThread
|
||||
void initializeHandwritingSpy(int displayId) {
|
||||
void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
|
||||
// When resetting, reuse resources if we are reinitializing on the same display.
|
||||
reset(displayId == mCurrentDisplayId);
|
||||
mCurrentDisplayId = displayId;
|
||||
@@ -110,8 +111,16 @@ final class HandwritingModeController {
|
||||
Slog.e(TAG, "Failed to create input surface");
|
||||
return;
|
||||
}
|
||||
mHandwritingSurface =
|
||||
new HandwritingEventReceiverSurface(name, displayId, surface, channel);
|
||||
|
||||
mHandwritingSurface = new HandwritingEventReceiverSurface(
|
||||
name, displayId, surface, channel);
|
||||
|
||||
// Configure the handwriting window to receive events over the focused window's bounds.
|
||||
mWindowManagerInternal.replaceInputSurfaceTouchableRegionWithWindowCrop(
|
||||
mHandwritingSurface.getSurface(),
|
||||
mHandwritingSurface.getInputWindowHandle(),
|
||||
focusedWindowToken);
|
||||
|
||||
// Use a dup of the input channel so that event processing can be paused by disposing the
|
||||
// event receiver without causing a fd hangup.
|
||||
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
|
||||
@@ -127,6 +136,10 @@ final class HandwritingModeController {
|
||||
return OptionalInt.of(mCurrentRequestId);
|
||||
}
|
||||
|
||||
boolean isStylusGestureOngoing() {
|
||||
return mRecordingGesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a {@link HandwritingSession} to transfer to the IME.
|
||||
*
|
||||
@@ -145,6 +158,10 @@ final class HandwritingModeController {
|
||||
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
|
||||
return null;
|
||||
}
|
||||
if (!mRecordingGesture) {
|
||||
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
|
||||
return null;
|
||||
}
|
||||
Objects.requireNonNull(mHandwritingEventReceiver,
|
||||
"Handwriting session was already transferred to IME.");
|
||||
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
|
||||
@@ -231,7 +248,7 @@ final class HandwritingModeController {
|
||||
mInkWindowInitRunnable = null;
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
||||
mRecordingGesture = false;
|
||||
mHandwritingBuffer.clear();
|
||||
return;
|
||||
|
||||
@@ -3439,6 +3439,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
Slog.e(TAG, "Stylus handwriting was not initialized.");
|
||||
return;
|
||||
}
|
||||
if (!mHwController.isStylusGestureOngoing()) {
|
||||
Slog.e(TAG, "There is no ongoing stylus gesture to start stylus handwriting.");
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started");
|
||||
final IInputMethodInvoker curMethod = getCurMethodLocked();
|
||||
if (curMethod != null) {
|
||||
@@ -4831,8 +4835,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
case MSG_RESET_HANDWRITING: {
|
||||
synchronized (ImfLock.class) {
|
||||
if (mBindingController.supportsStylusHandwriting()
|
||||
&& getCurMethodLocked() != null) {
|
||||
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
|
||||
&& getCurMethodLocked() != null && mCurFocusedWindow != null) {
|
||||
mHwController.initializeHandwritingSpy(
|
||||
mCurTokenDisplayId, mCurFocusedWindow);
|
||||
} else {
|
||||
mHwController.reset();
|
||||
}
|
||||
@@ -4860,7 +4865,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
session.getHandwritingChannel(), session.getRecordedEvents())) {
|
||||
// When failed to issue IPCs, re-initialize handwriting state.
|
||||
Slog.w(TAG, "Resetting handwriting mode.");
|
||||
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
|
||||
scheduleResetStylusHandwriting();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.view.IInputFilter;
|
||||
import android.view.IRemoteAnimationFinishedCallback;
|
||||
import android.view.IWindow;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -853,4 +854,26 @@ public abstract class WindowManagerInternal {
|
||||
* support handwriting (Scribe) by the IME.
|
||||
*/
|
||||
public abstract SurfaceControl getHandwritingSurfaceForDisplay(int displayId);
|
||||
|
||||
/**
|
||||
* Replaces the touchable region of the provided input surface with the crop of the window with
|
||||
* the provided token. This method will associate the inputSurface with a copy of
|
||||
* the given inputWindowHandle, where the copy is configured using
|
||||
* {@link InputWindowHandle#replaceTouchableRegionWithCrop(SurfaceControl)} with the surface
|
||||
* of the provided windowToken.
|
||||
*
|
||||
* This is a no-op if windowToken is not valid or the window is not found.
|
||||
*
|
||||
* This does not change any other properties of the inputSurface.
|
||||
*
|
||||
* This method exists to avoid leaking the window's SurfaceControl outside WindowManagerService.
|
||||
*
|
||||
* @param inputSurface The surface for which the touchable region should be set.
|
||||
* @param inputWindowHandle The {@link InputWindowHandle} for the input surface.
|
||||
* @param windowToken The window whose bounds should be used as the touchable region for the
|
||||
* inputSurface.
|
||||
*/
|
||||
public abstract void replaceInputSurfaceTouchableRegionWithWindowCrop(
|
||||
@NonNull SurfaceControl inputSurface, @NonNull InputWindowHandle inputWindowHandle,
|
||||
@NonNull IBinder windowToken);
|
||||
}
|
||||
|
||||
@@ -8162,6 +8162,27 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceInputSurfaceTouchableRegionWithWindowCrop(
|
||||
@NonNull SurfaceControl inputSurface,
|
||||
@NonNull InputWindowHandle inputWindowHandle,
|
||||
@NonNull IBinder windowToken) {
|
||||
synchronized (mGlobalLock) {
|
||||
final WindowState w = mWindowMap.get(windowToken);
|
||||
if (w == null) {
|
||||
return;
|
||||
}
|
||||
// Make a copy of the InputWindowHandle to avoid leaking the window's
|
||||
// SurfaceControl.
|
||||
final InputWindowHandle localHandle = new InputWindowHandle(inputWindowHandle);
|
||||
localHandle.replaceTouchableRegionWithCrop(w.getSurfaceControl());
|
||||
final SurfaceControl.Transaction t = mTransactionFactory.get();
|
||||
t.setInputWindowInfo(inputSurface, localHandle);
|
||||
t.apply();
|
||||
t.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void registerAppFreezeListener(AppFreezeListener listener) {
|
||||
|
||||
Reference in New Issue
Block a user