Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 003535dd authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge "Support multi-window handwriting without focus requirement on down" into tm-dev

parents 7d302d09 ae77af78
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -64,7 +64,9 @@ final class HandwritingEventReceiverSurface {
                        | InputConfig.INTERCEPTS_STYLUS
                        | InputConfig.TRUSTED_OVERLAY;

        // The touchable region of this input surface is not initially configured.
        // Configure the surface to receive stylus events across the entire display.
        mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);

        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        t.setInputWindowInfo(mInputSurface, mWindowHandle);
        t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
@@ -81,10 +83,6 @@ 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();
+17 −10
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ final class HandwritingModeController {
     * InputEventReceiver that batches events according to the current thread's Choreographer.
     */
    @UiThread
    void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
    void initializeHandwritingSpy(int displayId) {
        // When resetting, reuse resources if we are reinitializing on the same display.
        reset(displayId == mCurrentDisplayId);
        mCurrentDisplayId = displayId;
@@ -115,12 +115,6 @@ final class HandwritingModeController {
        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(
@@ -149,7 +143,8 @@ final class HandwritingModeController {
     */
    @UiThread
    @Nullable
    HandwritingSession startHandwritingSession(int requestId, int imePid, int imeUid) {
    HandwritingSession startHandwritingSession(
            int requestId, int imePid, int imeUid, IBinder focusedWindowToken) {
        if (mHandwritingSurface == null) {
            Slog.e(TAG, "Cannot start handwriting session: Handwriting was not initialized.");
            return null;
@@ -158,12 +153,20 @@ final class HandwritingModeController {
            Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
            return null;
        }
        if (!mRecordingGesture) {
        if (!mRecordingGesture || mHandwritingBuffer.isEmpty()) {
            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.");
        final MotionEvent downEvent = mHandwritingBuffer.get(0);
        assert (downEvent.getActionMasked() == MotionEvent.ACTION_DOWN);
        if (!mWindowManagerInternal.isPointInsideWindow(
                focusedWindowToken, mCurrentDisplayId, downEvent.getRawX(), downEvent.getRawY())) {
            Slog.e(TAG, "Cannot start handwriting session: "
                    + "Stylus gesture did not start inside the focused window.");
            return null;
        }
        if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);

        mInputManagerInternal.pilferPointers(mHandwritingSurface.getInputChannel().getToken());
@@ -226,13 +229,17 @@ final class HandwritingModeController {
        }

        if (!(ev instanceof MotionEvent)) {
            Slog.e("Stylus", "Received non-motion event in stylus monitor.");
            Slog.wtf(TAG, "Received non-motion event in stylus monitor.");
            return false;
        }
        final MotionEvent event = (MotionEvent) ev;
        if (!isStylusEvent(event)) {
            return false;
        }
        if (event.getDisplayId() != mCurrentDisplayId) {
            Slog.wtf(TAG, "Received stylus event associated with the incorrect display.");
            return false;
        }

        onStylusEvent(event);
        return true;
+5 −5
Original line number Diff line number Diff line
@@ -5118,9 +5118,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            case MSG_RESET_HANDWRITING: {
                synchronized (ImfLock.class) {
                    if (mBindingController.supportsStylusHandwriting()
                            && getCurMethodLocked() != null && mCurFocusedWindow != null) {
                        mHwController.initializeHandwritingSpy(
                                mCurTokenDisplayId, mCurFocusedWindow);
                            && getCurMethodLocked() != null) {
                        mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
                    } else {
                        mHwController.reset();
                    }
@@ -5130,14 +5129,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            case MSG_START_HANDWRITING:
                synchronized (ImfLock.class) {
                    IInputMethodInvoker curMethod = getCurMethodLocked();
                    if (curMethod == null) {
                    if (curMethod == null || mCurFocusedWindow == null) {
                        return true;
                    }
                    final HandwritingModeController.HandwritingSession session =
                            mHwController.startHandwritingSession(
                                    msg.arg1 /*requestId*/,
                                    msg.arg2 /*pid*/,
                                    mBindingController.getCurMethodUid());
                                    mBindingController.getCurMethodUid(),
                                    mCurFocusedWindow);
                    if (session == null) {
                        Slog.e(TAG,
                                "Failed to start handwriting session for requestId: " + msg.arg1);
+6 −19
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ 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;
@@ -862,24 +861,12 @@ public abstract class WindowManagerInternal {
    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.
     * Returns {@code true} if the given point is within the window bounds of the given window.
     *
     * 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.
     * @param windowToken the window whose bounds should be used for the hit test.
     * @param displayX the x coordinate of the test point in the display's coordinate space.
     * @param displayY the y coordinate of the test point in the display's coordinate space.
     */
    public abstract void replaceInputSurfaceTouchableRegionWithWindowCrop(
            @NonNull SurfaceControl inputSurface, @NonNull InputWindowHandle inputWindowHandle,
            @NonNull IBinder windowToken);
    public abstract boolean isPointInsideWindow(
            @NonNull IBinder windowToken, int displayId, float displayX, float displayY);
}
+6 −14
Original line number Diff line number Diff line
@@ -8250,23 +8250,15 @@ public class WindowManagerService extends IWindowManager.Stub
        }

        @Override
        public void replaceInputSurfaceTouchableRegionWithWindowCrop(
                @NonNull SurfaceControl inputSurface,
                @NonNull InputWindowHandle inputWindowHandle,
                @NonNull IBinder windowToken) {
        public boolean isPointInsideWindow(@NonNull IBinder windowToken, int displayId,
                float displayX, float displayY) {
            synchronized (mGlobalLock) {
                final WindowState w = mWindowMap.get(windowToken);
                if (w == null) {
                    return;
                if (w == null || w.getDisplayId() != displayId) {
                    return false;
                }
                // 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();

                return w.getBounds().contains((int) displayX, (int) displayY);
            }
        }
    }