1 /*
2  * Copyright (C) 2020 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.wm;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.graphics.Region;
22 import android.os.IBinder;
23 import android.os.InputConfig;
24 import android.view.IWindow;
25 import android.view.InputApplicationHandle;
26 import android.view.InputWindowHandle;
27 import android.view.InputWindowHandle.InputConfigFlags;
28 import android.view.SurfaceControl;
29 import android.view.WindowManager;
30 
31 import java.util.Objects;
32 
33 /**
34  * The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary
35  * updates to surface, e.g. if there are no changes, then skip invocation of
36  * {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}.
37  * It also sets the {@link InputConfigFlags} values for the input window.
38  */
39 class InputWindowHandleWrapper {
40 
41     /** The wrapped handle should not be directly exposed to avoid untracked changes. */
42     private final @NonNull InputWindowHandle mHandle;
43 
44     /** Whether the {@link #mHandle} is changed. */
45     private boolean mChanged = true;
46 
InputWindowHandleWrapper(@onNull InputWindowHandle handle)47     InputWindowHandleWrapper(@NonNull InputWindowHandle handle) {
48         mHandle = handle;
49     }
50 
51     /**
52      * Returns {@code true} if the input window handle has changed since the last invocation of
53      * {@link #applyChangesToSurface(SurfaceControl.Transaction, SurfaceControl)}}
54      */
isChanged()55     boolean isChanged() {
56         return mChanged;
57     }
58 
forceChange()59     void forceChange() {
60         mChanged = true;
61     }
62 
applyChangesToSurface(@onNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc)63     void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
64         t.setInputWindowInfo(sc, mHandle);
65         mChanged = false;
66     }
67 
getDisplayId()68     int getDisplayId() {
69         return mHandle.displayId;
70     }
71 
isFocusable()72     boolean isFocusable() {
73         return (mHandle.inputConfig & InputConfig.NOT_FOCUSABLE) == 0;
74     }
75 
isPaused()76     boolean isPaused() {
77         return (mHandle.inputConfig & InputConfig.PAUSE_DISPATCHING) != 0;
78     }
79 
isTrustedOverlay()80     boolean isTrustedOverlay() {
81         return (mHandle.inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
82     }
83 
hasWallpaper()84     boolean hasWallpaper() {
85         return (mHandle.inputConfig & InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER)
86                 != 0;
87     }
88 
getInputApplicationHandle()89     InputApplicationHandle getInputApplicationHandle() {
90         return mHandle.inputApplicationHandle;
91     }
92 
setInputApplicationHandle(InputApplicationHandle handle)93     void setInputApplicationHandle(InputApplicationHandle handle) {
94         if (mHandle.inputApplicationHandle == handle) {
95             return;
96         }
97         mHandle.inputApplicationHandle = handle;
98         mChanged = true;
99     }
100 
setToken(IBinder token)101     void setToken(IBinder token) {
102         if (mHandle.token == token) {
103             return;
104         }
105         mHandle.token = token;
106         mChanged = true;
107     }
108 
setName(String name)109     void setName(String name) {
110         if (Objects.equals(mHandle.name, name)) {
111             return;
112         }
113         mHandle.name = name;
114         mChanged = true;
115     }
116 
setLayoutParamsFlags(@indowManager.LayoutParams.Flags int flags)117     void setLayoutParamsFlags(@WindowManager.LayoutParams.Flags int flags) {
118         if (mHandle.layoutParamsFlags == flags) {
119             return;
120         }
121         mHandle.layoutParamsFlags = flags;
122         mChanged = true;
123     }
124 
setLayoutParamsType(int type)125     void setLayoutParamsType(int type) {
126         if (mHandle.layoutParamsType == type) {
127             return;
128         }
129         mHandle.layoutParamsType = type;
130         mChanged = true;
131     }
132 
setDispatchingTimeoutMillis(long timeout)133     void setDispatchingTimeoutMillis(long timeout) {
134         if (mHandle.dispatchingTimeoutMillis == timeout) {
135             return;
136         }
137         mHandle.dispatchingTimeoutMillis = timeout;
138         mChanged = true;
139     }
140 
setTouchableRegion(Region region)141     void setTouchableRegion(Region region) {
142         if (mHandle.touchableRegion.equals(region)) {
143             return;
144         }
145         mHandle.touchableRegion.set(region);
146         mChanged = true;
147     }
148 
clearTouchableRegion()149     void clearTouchableRegion() {
150         if (mHandle.touchableRegion.isEmpty()) {
151             return;
152         }
153         mHandle.touchableRegion.setEmpty();
154         mChanged = true;
155     }
156 
setFocusable(boolean focusable)157     void setFocusable(boolean focusable) {
158         if (isFocusable() == focusable) {
159             return;
160         }
161         mHandle.setInputConfig(InputConfig.NOT_FOCUSABLE, !focusable);
162         mChanged = true;
163     }
164 
setTouchOcclusionMode(int mode)165     void setTouchOcclusionMode(int mode) {
166         if (mHandle.touchOcclusionMode == mode) {
167             return;
168         }
169         mHandle.touchOcclusionMode = mode;
170         mChanged = true;
171     }
172 
setHasWallpaper(boolean hasWallpaper)173     void setHasWallpaper(boolean hasWallpaper) {
174         if (this.hasWallpaper() == hasWallpaper) {
175             return;
176         }
177         mHandle.setInputConfig(InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
178                 hasWallpaper);
179         mChanged = true;
180     }
181 
setPaused(boolean paused)182     void setPaused(boolean paused) {
183         if (isPaused() == paused) {
184             return;
185         }
186         mHandle.setInputConfig(InputConfig.PAUSE_DISPATCHING, paused);
187         mChanged = true;
188     }
189 
setTrustedOverlay(boolean trustedOverlay)190     void setTrustedOverlay(boolean trustedOverlay) {
191         if (isTrustedOverlay() == trustedOverlay) {
192             return;
193         }
194         mHandle.setInputConfig(InputConfig.TRUSTED_OVERLAY, trustedOverlay);
195         mChanged = true;
196     }
197 
setOwnerPid(int pid)198     void setOwnerPid(int pid) {
199         if (mHandle.ownerPid == pid) {
200             return;
201         }
202         mHandle.ownerPid = pid;
203         mChanged = true;
204     }
205 
setOwnerUid(int uid)206     void setOwnerUid(int uid) {
207         if (mHandle.ownerUid == uid) {
208             return;
209         }
210         mHandle.ownerUid = uid;
211         mChanged = true;
212     }
213 
setPackageName(String packageName)214     void setPackageName(String packageName) {
215         if (Objects.equals(mHandle.packageName, packageName)) {
216             return;
217         }
218         mHandle.packageName = packageName;
219         mChanged = true;
220     }
221 
setDisplayId(int displayId)222     void setDisplayId(int displayId) {
223         if (mHandle.displayId == displayId) {
224             return;
225         }
226         mHandle.displayId = displayId;
227         mChanged = true;
228     }
229 
setFrame(int left, int top, int right, int bottom)230     void setFrame(int left, int top, int right, int bottom) {
231         if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
232                 && mHandle.frameBottom == bottom) {
233             return;
234         }
235         mHandle.frameLeft = left;
236         mHandle.frameTop = top;
237         mHandle.frameRight = right;
238         mHandle.frameBottom = bottom;
239         mChanged = true;
240     }
241 
setSurfaceInset(int inset)242     void setSurfaceInset(int inset) {
243         if (mHandle.surfaceInset == inset) {
244             return;
245         }
246         mHandle.surfaceInset = inset;
247         mChanged = true;
248     }
249 
setScaleFactor(float scale)250     void setScaleFactor(float scale) {
251         if (mHandle.scaleFactor == scale) {
252             return;
253         }
254         mHandle.scaleFactor = scale;
255         mChanged = true;
256     }
257 
setTouchableRegionCrop(@ullable SurfaceControl bounds)258     void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
259         if (mHandle.touchableRegionSurfaceControl.get() == bounds) {
260             return;
261         }
262         mHandle.setTouchableRegionCrop(bounds);
263         mChanged = true;
264     }
265 
setReplaceTouchableRegionWithCrop(boolean replace)266     void setReplaceTouchableRegionWithCrop(boolean replace) {
267         if (mHandle.replaceTouchableRegionWithCrop == replace) {
268             return;
269         }
270         mHandle.replaceTouchableRegionWithCrop = replace;
271         mChanged = true;
272     }
273 
setWindowToken(IWindow windowToken)274     void setWindowToken(IWindow windowToken) {
275         if (mHandle.getWindow() == windowToken) {
276             return;
277         }
278         mHandle.setWindowToken(windowToken);
279         mChanged = true;
280     }
281 
setInputConfigMasked(@nputConfigFlags int inputConfig, @InputConfigFlags int mask)282     void setInputConfigMasked(@InputConfigFlags int inputConfig, @InputConfigFlags int mask) {
283         final int inputConfigMasked = inputConfig & mask;
284         if (inputConfigMasked == (mHandle.inputConfig & mask)) {
285             return;
286         }
287         mHandle.inputConfig &= ~mask;
288         mHandle.inputConfig |= inputConfigMasked;
289         mChanged = true;
290     }
291 
setFocusTransferTarget(IBinder toToken)292     void setFocusTransferTarget(IBinder toToken) {
293         if (mHandle.focusTransferTarget == toToken) {
294             return;
295         }
296         mHandle.focusTransferTarget = toToken;
297         mChanged = true;
298     }
299 
300     @Override
toString()301     public String toString() {
302         return mHandle + ", changed=" + mChanged;
303     }
304 }
305