1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.inputmethod; 18 19 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; 20 21 import android.annotation.NonNull; 22 import android.content.Context; 23 import android.graphics.Rect; 24 import android.graphics.Region; 25 import android.os.InputConfig; 26 import android.os.Process; 27 import android.util.Slog; 28 import android.view.InputApplicationHandle; 29 import android.view.InputChannel; 30 import android.view.InputWindowHandle; 31 import android.view.SurfaceControl; 32 import android.view.WindowManager; 33 import android.view.WindowMetrics; 34 import android.view.inputmethod.Flags; 35 36 import com.android.server.input.InputManagerService; 37 38 final class HandwritingEventReceiverSurface { 39 40 public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName(); 41 static final boolean DEBUG = HandwritingModeController.DEBUG; 42 43 private final InputWindowHandle mWindowHandle; 44 private final InputChannel mClientChannel; 45 private final SurfaceControl mInputSurface; 46 private boolean mIsIntercepting; 47 HandwritingEventReceiverSurface(Context context, String name, int displayId, @NonNull SurfaceControl sc, @NonNull InputChannel inputChannel)48 HandwritingEventReceiverSurface(Context context, String name, int displayId, 49 @NonNull SurfaceControl sc, @NonNull InputChannel inputChannel) { 50 mClientChannel = inputChannel; 51 mInputSurface = sc; 52 53 mWindowHandle = new InputWindowHandle(new InputApplicationHandle(null, name, 54 DEFAULT_DISPATCHING_TIMEOUT_MILLIS), displayId); 55 mWindowHandle.name = name; 56 mWindowHandle.token = mClientChannel.getToken(); 57 mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 58 mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; 59 mWindowHandle.ownerPid = Process.myPid(); 60 mWindowHandle.ownerUid = Process.myUid(); 61 mWindowHandle.scaleFactor = 1.0f; 62 mWindowHandle.inputConfig = 63 InputConfig.NOT_FOCUSABLE 64 | InputConfig.NOT_TOUCHABLE 65 | InputConfig.SPY 66 | InputConfig.INTERCEPTS_STYLUS; 67 68 Rect bounds = null; 69 if (Flags.adaptiveHandwritingBounds()) { 70 mWindowHandle.setTouchableRegionCrop(mInputSurface); 71 // Default touchable area to getMaximumWindowMetrics() 72 WindowMetrics windowMetrics = context.getSystemService(WindowManager.class) 73 .getMaximumWindowMetrics(); 74 bounds = windowMetrics.getBounds(); 75 if (DEBUG) Slog.d(TAG, "initial handwriting touchable bounds: " + bounds); 76 mWindowHandle.setTouchableRegion(windowMetrics.getBounds()); 77 } else { 78 // Configure the surface to receive stylus events across the entire display. 79 mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); 80 } 81 82 final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 83 mWindowHandle.setTrustedOverlay(t, mInputSurface, true); 84 t.setInputWindowInfo(mInputSurface, mWindowHandle); 85 t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE); 86 t.setPosition(mInputSurface, 0, 0); 87 if (Flags.adaptiveHandwritingBounds()) { 88 // crop to parent surface if null, else bounds. 89 t.setCrop(mInputSurface, bounds); 90 } else { 91 t.setCrop(mInputSurface, null /* crop to parent surface */); 92 } 93 t.show(mInputSurface); 94 t.apply(); 95 96 mIsIntercepting = false; 97 } 98 startIntercepting(int imePid, int imeUid)99 void startIntercepting(int imePid, int imeUid) { 100 mWindowHandle.ownerPid = imePid; 101 mWindowHandle.ownerUid = imeUid; 102 mWindowHandle.inputConfig &= ~InputConfig.SPY; 103 104 if (Flags.adaptiveHandwritingBounds()) { 105 // watch outside touch to finish handwriting. 106 mWindowHandle.inputConfig |= InputConfig.WATCH_OUTSIDE_TOUCH; 107 } 108 new SurfaceControl.Transaction() 109 .setInputWindowInfo(mInputSurface, mWindowHandle) 110 .apply(); 111 mIsIntercepting = true; 112 } 113 setTouchableRegion(Region touchableRegion)114 void setTouchableRegion(Region touchableRegion) { 115 mWindowHandle.touchableRegion.set(touchableRegion); 116 new SurfaceControl.Transaction() 117 .setInputWindowInfo(mInputSurface, mWindowHandle) 118 .apply(); 119 } 120 setNotTouchable(boolean notTouchable)121 void setNotTouchable(boolean notTouchable) { 122 if (notTouchable) { 123 mWindowHandle.inputConfig |= InputConfig.NOT_TOUCHABLE; 124 } else { 125 mWindowHandle.inputConfig &= ~InputConfig.NOT_TOUCHABLE; 126 } 127 new SurfaceControl.Transaction() 128 .setInputWindowInfo(mInputSurface, mWindowHandle) 129 .apply(); 130 } 131 isIntercepting()132 boolean isIntercepting() { 133 return mIsIntercepting; 134 } 135 remove()136 void remove() { 137 final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 138 t.remove(mInputSurface); 139 t.apply(); 140 } 141 getInputChannel()142 InputChannel getInputChannel() { 143 return mClientChannel; 144 } 145 getSurface()146 SurfaceControl getSurface() { 147 return mInputSurface; 148 } 149 getInputWindowHandle()150 InputWindowHandle getInputWindowHandle() { 151 return mWindowHandle; 152 } 153 } 154