• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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