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;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringBuilder(name != null ? name : "")
|
return new StringBuilder(name != null ? name : "")
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import android.view.InputWindowHandle;
|
|||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
|
||||||
final class HandwritingEventReceiverSurface {
|
final class HandwritingEventReceiverSurface {
|
||||||
|
|
||||||
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
|
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.
|
// TODO(b/217538817): Specify the ordering in WM by usage.
|
||||||
private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
|
private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
|
||||||
|
|
||||||
private final InputApplicationHandle mApplicationHandle;
|
|
||||||
private final InputWindowHandle mWindowHandle;
|
private final InputWindowHandle mWindowHandle;
|
||||||
private final InputChannel mClientChannel;
|
private final InputChannel mClientChannel;
|
||||||
private final SurfaceControl mInputSurface;
|
private final SurfaceControl mInputSurface;
|
||||||
@@ -47,13 +45,11 @@ final class HandwritingEventReceiverSurface {
|
|||||||
|
|
||||||
HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
|
HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
|
||||||
@NonNull InputChannel inputChannel) {
|
@NonNull InputChannel inputChannel) {
|
||||||
mApplicationHandle = new InputApplicationHandle(null, name,
|
|
||||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
|
|
||||||
|
|
||||||
mClientChannel = inputChannel;
|
mClientChannel = inputChannel;
|
||||||
mInputSurface = sc;
|
mInputSurface = sc;
|
||||||
|
|
||||||
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
|
mWindowHandle = new InputWindowHandle(new InputApplicationHandle(null, name,
|
||||||
|
DEFAULT_DISPATCHING_TIMEOUT_MILLIS), displayId);
|
||||||
mWindowHandle.name = name;
|
mWindowHandle.name = name;
|
||||||
mWindowHandle.token = mClientChannel.getToken();
|
mWindowHandle.token = mClientChannel.getToken();
|
||||||
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
|
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
|
||||||
@@ -61,7 +57,6 @@ final class HandwritingEventReceiverSurface {
|
|||||||
mWindowHandle.ownerPid = Process.myPid();
|
mWindowHandle.ownerPid = Process.myPid();
|
||||||
mWindowHandle.ownerUid = Process.myUid();
|
mWindowHandle.ownerUid = Process.myUid();
|
||||||
mWindowHandle.scaleFactor = 1.0f;
|
mWindowHandle.scaleFactor = 1.0f;
|
||||||
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
|
|
||||||
mWindowHandle.inputConfig =
|
mWindowHandle.inputConfig =
|
||||||
InputConfig.NOT_FOCUSABLE
|
InputConfig.NOT_FOCUSABLE
|
||||||
| InputConfig.NOT_TOUCHABLE
|
| InputConfig.NOT_TOUCHABLE
|
||||||
@@ -69,6 +64,7 @@ final class HandwritingEventReceiverSurface {
|
|||||||
| InputConfig.INTERCEPTS_STYLUS
|
| InputConfig.INTERCEPTS_STYLUS
|
||||||
| InputConfig.TRUSTED_OVERLAY;
|
| InputConfig.TRUSTED_OVERLAY;
|
||||||
|
|
||||||
|
// The touchable region of this input surface is not initially configured.
|
||||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||||
t.setInputWindowInfo(mInputSurface, mWindowHandle);
|
t.setInputWindowInfo(mInputSurface, mWindowHandle);
|
||||||
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
|
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
|
||||||
@@ -85,6 +81,10 @@ final class HandwritingEventReceiverSurface {
|
|||||||
mWindowHandle.ownerUid = imeUid;
|
mWindowHandle.ownerUid = imeUid;
|
||||||
mWindowHandle.inputConfig &= ~InputConfig.SPY;
|
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()
|
new SurfaceControl.Transaction()
|
||||||
.setInputWindowInfo(mInputSurface, mWindowHandle)
|
.setInputWindowInfo(mInputSurface, mWindowHandle)
|
||||||
.apply();
|
.apply();
|
||||||
@@ -108,4 +108,8 @@ final class HandwritingEventReceiverSurface {
|
|||||||
SurfaceControl getSurface() {
|
SurfaceControl getSurface() {
|
||||||
return mInputSurface;
|
return mInputSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputWindowHandle getInputWindowHandle() {
|
||||||
|
return mWindowHandle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.annotation.AnyThread;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UiThread;
|
import android.annotation.UiThread;
|
||||||
import android.hardware.input.InputManagerInternal;
|
import android.hardware.input.InputManagerInternal;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.BatchedInputEventReceiver;
|
import android.view.BatchedInputEventReceiver;
|
||||||
@@ -90,7 +91,7 @@ final class HandwritingModeController {
|
|||||||
* InputEventReceiver that batches events according to the current thread's Choreographer.
|
* InputEventReceiver that batches events according to the current thread's Choreographer.
|
||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
void initializeHandwritingSpy(int displayId) {
|
void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
|
||||||
// When resetting, reuse resources if we are reinitializing on the same display.
|
// When resetting, reuse resources if we are reinitializing on the same display.
|
||||||
reset(displayId == mCurrentDisplayId);
|
reset(displayId == mCurrentDisplayId);
|
||||||
mCurrentDisplayId = displayId;
|
mCurrentDisplayId = displayId;
|
||||||
@@ -110,8 +111,16 @@ final class HandwritingModeController {
|
|||||||
Slog.e(TAG, "Failed to create input surface");
|
Slog.e(TAG, "Failed to create input surface");
|
||||||
return;
|
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
|
// Use a dup of the input channel so that event processing can be paused by disposing the
|
||||||
// event receiver without causing a fd hangup.
|
// event receiver without causing a fd hangup.
|
||||||
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
|
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
|
||||||
@@ -127,6 +136,10 @@ final class HandwritingModeController {
|
|||||||
return OptionalInt.of(mCurrentRequestId);
|
return OptionalInt.of(mCurrentRequestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isStylusGestureOngoing() {
|
||||||
|
return mRecordingGesture;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a {@link HandwritingSession} to transfer to the IME.
|
* 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);
|
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!mRecordingGesture) {
|
||||||
|
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Objects.requireNonNull(mHandwritingEventReceiver,
|
Objects.requireNonNull(mHandwritingEventReceiver,
|
||||||
"Handwriting session was already transferred to IME.");
|
"Handwriting session was already transferred to IME.");
|
||||||
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
|
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
|
||||||
@@ -231,7 +248,7 @@ final class HandwritingModeController {
|
|||||||
mInkWindowInitRunnable = null;
|
mInkWindowInitRunnable = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == MotionEvent.ACTION_UP) {
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
||||||
mRecordingGesture = false;
|
mRecordingGesture = false;
|
||||||
mHandwritingBuffer.clear();
|
mHandwritingBuffer.clear();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3439,6 +3439,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
Slog.e(TAG, "Stylus handwriting was not initialized.");
|
Slog.e(TAG, "Stylus handwriting was not initialized.");
|
||||||
return;
|
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");
|
if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started");
|
||||||
final IInputMethodInvoker curMethod = getCurMethodLocked();
|
final IInputMethodInvoker curMethod = getCurMethodLocked();
|
||||||
if (curMethod != null) {
|
if (curMethod != null) {
|
||||||
@@ -4831,8 +4835,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
case MSG_RESET_HANDWRITING: {
|
case MSG_RESET_HANDWRITING: {
|
||||||
synchronized (ImfLock.class) {
|
synchronized (ImfLock.class) {
|
||||||
if (mBindingController.supportsStylusHandwriting()
|
if (mBindingController.supportsStylusHandwriting()
|
||||||
&& getCurMethodLocked() != null) {
|
&& getCurMethodLocked() != null && mCurFocusedWindow != null) {
|
||||||
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
|
mHwController.initializeHandwritingSpy(
|
||||||
|
mCurTokenDisplayId, mCurFocusedWindow);
|
||||||
} else {
|
} else {
|
||||||
mHwController.reset();
|
mHwController.reset();
|
||||||
}
|
}
|
||||||
@@ -4860,7 +4865,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
session.getHandwritingChannel(), session.getRecordedEvents())) {
|
session.getHandwritingChannel(), session.getRecordedEvents())) {
|
||||||
// When failed to issue IPCs, re-initialize handwriting state.
|
// When failed to issue IPCs, re-initialize handwriting state.
|
||||||
Slog.w(TAG, "Resetting handwriting mode.");
|
Slog.w(TAG, "Resetting handwriting mode.");
|
||||||
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
|
scheduleResetStylusHandwriting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.view.IInputFilter;
|
|||||||
import android.view.IRemoteAnimationFinishedCallback;
|
import android.view.IRemoteAnimationFinishedCallback;
|
||||||
import android.view.IWindow;
|
import android.view.IWindow;
|
||||||
import android.view.InputChannel;
|
import android.view.InputChannel;
|
||||||
|
import android.view.InputWindowHandle;
|
||||||
import android.view.MagnificationSpec;
|
import android.view.MagnificationSpec;
|
||||||
import android.view.RemoteAnimationTarget;
|
import android.view.RemoteAnimationTarget;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
@@ -853,4 +854,26 @@ public abstract class WindowManagerInternal {
|
|||||||
* support handwriting (Scribe) by the IME.
|
* support handwriting (Scribe) by the IME.
|
||||||
*/
|
*/
|
||||||
public abstract SurfaceControl getHandwritingSurfaceForDisplay(int displayId);
|
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();
|
.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) {
|
void registerAppFreezeListener(AppFreezeListener listener) {
|
||||||
|
|||||||
Reference in New Issue
Block a user