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.os.InputConfig;
23 import android.os.Process;
24 import android.view.InputApplicationHandle;
25 import android.view.InputChannel;
26 import android.view.InputWindowHandle;
27 import android.view.SurfaceControl;
28 import android.view.WindowManager;
29 
30 import com.android.server.input.InputManagerService;
31 
32 final class HandwritingEventReceiverSurface {
33 
34     public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
35     static final boolean DEBUG = HandwritingModeController.DEBUG;
36 
37     private final InputWindowHandle mWindowHandle;
38     private final InputChannel mClientChannel;
39     private final SurfaceControl mInputSurface;
40     private boolean mIsIntercepting;
41 
HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc, @NonNull InputChannel inputChannel)42     HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
43             @NonNull InputChannel inputChannel) {
44         mClientChannel = inputChannel;
45         mInputSurface = sc;
46 
47         mWindowHandle = new InputWindowHandle(new InputApplicationHandle(null, name,
48                 DEFAULT_DISPATCHING_TIMEOUT_MILLIS), displayId);
49         mWindowHandle.name = name;
50         mWindowHandle.token = mClientChannel.getToken();
51         mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
52         mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
53         mWindowHandle.ownerPid = Process.myPid();
54         mWindowHandle.ownerUid = Process.myUid();
55         mWindowHandle.scaleFactor = 1.0f;
56         mWindowHandle.inputConfig =
57                 InputConfig.NOT_FOCUSABLE
58                         | InputConfig.NOT_TOUCHABLE
59                         | InputConfig.SPY
60                         | InputConfig.INTERCEPTS_STYLUS;
61 
62         // Configure the surface to receive stylus events across the entire display.
63         mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
64 
65         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
66         mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
67         t.setInputWindowInfo(mInputSurface, mWindowHandle);
68         t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
69         t.setPosition(mInputSurface, 0, 0);
70         t.setCrop(mInputSurface, null /* crop to parent surface */);
71         t.show(mInputSurface);
72         t.apply();
73 
74         mIsIntercepting = false;
75     }
76 
startIntercepting(int imePid, int imeUid)77     void startIntercepting(int imePid, int imeUid) {
78         mWindowHandle.ownerPid = imePid;
79         mWindowHandle.ownerUid = imeUid;
80         mWindowHandle.inputConfig &= ~InputConfig.SPY;
81 
82         new SurfaceControl.Transaction()
83                 .setInputWindowInfo(mInputSurface, mWindowHandle)
84                 .apply();
85         mIsIntercepting = true;
86     }
87 
setNotTouchable(boolean notTouchable)88     void setNotTouchable(boolean notTouchable) {
89         if (notTouchable) {
90             mWindowHandle.inputConfig |= InputConfig.NOT_TOUCHABLE;
91         } else {
92             mWindowHandle.inputConfig &=  ~InputConfig.NOT_TOUCHABLE;
93         }
94         new SurfaceControl.Transaction()
95                 .setInputWindowInfo(mInputSurface, mWindowHandle)
96                 .apply();
97     }
98 
isIntercepting()99     boolean isIntercepting() {
100         return mIsIntercepting;
101     }
102 
remove()103     void remove() {
104         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
105         t.remove(mInputSurface);
106         t.apply();
107     }
108 
getInputChannel()109     InputChannel getInputChannel() {
110         return mClientChannel;
111     }
112 
getSurface()113     SurfaceControl getSurface() {
114         return mInputSurface;
115     }
116 
getInputWindowHandle()117     InputWindowHandle getInputWindowHandle() {
118         return mWindowHandle;
119     }
120 }
121