blob: 8abfde2c5c36187166ff5dbfdb69b911c13925ec [file] [log] [blame]
Svetoslav8e3feb12014-02-24 13:46:47 -08001/*
2 * Copyright (C) 2014 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
17package com.android.server.wm;
18
Vishnu Naire86bd982018-11-28 13:23:17 -080019import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
Phil Weaverb2779532017-12-18 17:09:32 -080020import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
Phil Weaverd321075e2017-06-13 09:13:35 -070021import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
Phil Weaverd321075e2017-06-13 09:13:35 -070022
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080023import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
24import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Jackal Guof3823712019-05-20 10:16:06 +080025import static com.android.server.wm.utils.RegionUtils.forEachRect;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080026
Svetoslav8e3feb12014-02-24 13:46:47 -080027import android.animation.ObjectAnimator;
28import android.animation.ValueAnimator;
Alan Viverette59e53a12016-03-28 13:41:32 -040029import android.annotation.NonNull;
Svetoslav8e3feb12014-02-24 13:46:47 -080030import android.app.Service;
31import android.content.Context;
32import android.graphics.Canvas;
33import android.graphics.Color;
34import android.graphics.Matrix;
35import android.graphics.Paint;
36import android.graphics.Path;
37import android.graphics.PixelFormat;
38import android.graphics.Point;
39import android.graphics.PorterDuff.Mode;
40import android.graphics.Rect;
41import android.graphics.RectF;
42import android.graphics.Region;
43import android.os.Handler;
44import android.os.IBinder;
45import android.os.Looper;
46import android.os.Message;
47import android.util.ArraySet;
Svetoslav8e3feb12014-02-24 13:46:47 -080048import android.util.Slog;
49import android.util.SparseArray;
50import android.util.TypedValue;
Rhed Jao02655dc2018-10-30 20:44:52 +080051import android.view.Display;
Svetoslav8e3feb12014-02-24 13:46:47 -080052import android.view.MagnificationSpec;
53import android.view.Surface;
54import android.view.Surface.OutOfResourcesException;
55import android.view.SurfaceControl;
Svetoslavf7174e82014-06-12 11:29:35 -070056import android.view.ViewConfiguration;
Svetoslav8e3feb12014-02-24 13:46:47 -080057import android.view.WindowInfo;
58import android.view.WindowManager;
Svetoslav8e3feb12014-02-24 13:46:47 -080059import android.view.animation.DecelerateInterpolator;
60import android.view.animation.Interpolator;
61
62import com.android.internal.R;
63import com.android.internal.os.SomeArgs;
Adrian Roose99bc052017-11-20 17:55:31 +010064import com.android.server.policy.WindowManagerPolicy;
65import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
66import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
Svetoslav8e3feb12014-02-24 13:46:47 -080067
68import java.util.ArrayList;
Allen Hairf20ac2c2016-02-11 17:42:59 -080069import java.util.HashSet;
Svetoslav8e3feb12014-02-24 13:46:47 -080070import java.util.List;
71import java.util.Set;
72
73/**
kopriva82c591b2018-10-08 15:57:00 -070074 * This class contains the accessibility related logic of the window manager.
Svetoslav8e3feb12014-02-24 13:46:47 -080075 */
76final class AccessibilityController {
77
Robert Carre625fcf2017-09-01 12:36:28 -070078 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -080079
80 private static final float[] sTempFloats = new float[9];
81
82 public AccessibilityController(WindowManagerService service) {
Robert Carre625fcf2017-09-01 12:36:28 -070083 mService = service;
Svetoslav8e3feb12014-02-24 13:46:47 -080084 }
85
Rhed Jao02655dc2018-10-30 20:44:52 +080086 private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
Svetoslav8e3feb12014-02-24 13:46:47 -080087
88 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
89
Rhed Jao02655dc2018-10-30 20:44:52 +080090 public boolean setMagnificationCallbacksLocked(int displayId,
91 MagnificationCallbacks callbacks) {
92 boolean result = false;
Svetoslav8e3feb12014-02-24 13:46:47 -080093 if (callbacks != null) {
Rhed Jao02655dc2018-10-30 20:44:52 +080094 if (mDisplayMagnifiers.get(displayId) != null) {
Svetoslav8e3feb12014-02-24 13:46:47 -080095 throw new IllegalStateException("Magnification callbacks already set!");
96 }
Rhed Jao02655dc2018-10-30 20:44:52 +080097 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
98 if (dc != null) {
99 final Display display = dc.getDisplay();
100 if (display != null && display.getType() != Display.TYPE_OVERLAY) {
101 mDisplayMagnifiers.put(displayId, new DisplayMagnifier(
102 mService, dc, display, callbacks));
103 result = true;
104 }
105 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800106 } else {
Rhed Jao02655dc2018-10-30 20:44:52 +0800107 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
108 if (displayMagnifier == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800109 throw new IllegalStateException("Magnification callbacks already cleared!");
110 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800111 displayMagnifier.destroyLocked();
112 mDisplayMagnifiers.remove(displayId);
113 result = true;
Svetoslav8e3feb12014-02-24 13:46:47 -0800114 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800115 return result;
Svetoslav8e3feb12014-02-24 13:46:47 -0800116 }
117
118 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
119 if (callback != null) {
120 if (mWindowsForAccessibilityObserver != null) {
121 throw new IllegalStateException(
122 "Windows for accessibility callback already set!");
123 }
124 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
Robert Carre625fcf2017-09-01 12:36:28 -0700125 mService, callback);
Svetoslav8e3feb12014-02-24 13:46:47 -0800126 } else {
127 if (mWindowsForAccessibilityObserver == null) {
128 throw new IllegalStateException(
129 "Windows for accessibility callback already cleared!");
130 }
131 mWindowsForAccessibilityObserver = null;
132 }
133 }
134
Phil Weaverc72faad2018-07-24 10:53:01 -0700135 public void performComputeChangedWindowsNotLocked(boolean forceSend) {
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700136 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700137 synchronized (mService) {
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700138 observer = mWindowsForAccessibilityObserver;
139 }
140 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700141 observer.performComputeChangedWindowsNotLocked(forceSend);
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700142 }
143 }
144
Rhed Jao02655dc2018-10-30 20:44:52 +0800145 public void setMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
146 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
147 if (displayMagnifier != null) {
148 displayMagnifier.setMagnificationSpecLocked(spec);
Svetoslav8e3feb12014-02-24 13:46:47 -0800149 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800150 // TODO: support multi-display for windows observer
151 if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
Svetoslavf7174e82014-06-12 11:29:35 -0700152 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800153 }
154 }
155
Rhed Jao02655dc2018-10-30 20:44:52 +0800156 public void getMagnificationRegionLocked(int displayId, Region outMagnificationRegion) {
157 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
158 if (displayMagnifier != null) {
159 displayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400160 }
161 }
162
Rhed Jao02655dc2018-10-30 20:44:52 +0800163 public void onRectangleOnScreenRequestedLocked(int displayId, Rect rectangle) {
164 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
165 if (displayMagnifier != null) {
166 displayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800167 }
168 // Not relevant for the window observer.
169 }
170
Rhed Jao02655dc2018-10-30 20:44:52 +0800171 public void onWindowLayersChangedLocked(int displayId) {
172 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
173 if (displayMagnifier != null) {
174 displayMagnifier.onWindowLayersChangedLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800175 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800176 // TODO: support multi-display for windows observer
177 if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
Svetoslavf7174e82014-06-12 11:29:35 -0700178 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800179 }
180 }
181
Andrii Kulian8ee72852017-03-10 10:36:45 -0800182 public void onRotationChangedLocked(DisplayContent displayContent) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800183 final int displayId = displayContent.getDisplayId();
184 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
185 if (displayMagnifier != null) {
186 displayMagnifier.onRotationChangedLocked(displayContent);
Svetoslav8e3feb12014-02-24 13:46:47 -0800187 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800188 // TODO: support multi-display for windows observer
189 if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
Svetoslavf7174e82014-06-12 11:29:35 -0700190 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800191 }
192 }
193
194 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800195 final int displayId = windowState.getDisplayId();
196 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
197 if (displayMagnifier != null) {
198 displayMagnifier.onAppWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800199 }
200 // Not relevant for the window observer.
201 }
202
203 public void onWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800204 final int displayId = windowState.getDisplayId();
205 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
206 if (displayMagnifier != null) {
207 displayMagnifier.onWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800208 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800209 // TODO: support multi-display for windows observer
210 if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
Svetoslavf7174e82014-06-12 11:29:35 -0700211 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800212 }
213 }
214
Svetoslav3a0d8782014-12-04 12:50:11 -0800215 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800216 // Not relevant for the display magnifier.
217
Svetoslav3a0d8782014-12-04 12:50:11 -0800218 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700219 synchronized (mService) {
Svetoslav3a0d8782014-12-04 12:50:11 -0800220 observer = mWindowsForAccessibilityObserver;
221 }
222 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700223 observer.performComputeChangedWindowsNotLocked(false);
Svetoslav8e3feb12014-02-24 13:46:47 -0800224 }
225 }
226
Svetoslavf7174e82014-06-12 11:29:35 -0700227 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700228 // Not relevant for the display magnifier.
229
230 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700231 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700232 }
233 }
234
Svetoslav8e3feb12014-02-24 13:46:47 -0800235 /** NOTE: This has to be called within a surface transaction. */
Rhed Jao02655dc2018-10-30 20:44:52 +0800236 public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) {
237 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
238 if (displayMagnifier != null) {
239 displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800240 }
241 // Not relevant for the window observer.
242 }
243
244 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800245 final int displayId = windowState.getDisplayId();
246 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
247 if (displayMagnifier != null) {
248 return displayMagnifier.getMagnificationSpecForWindowLocked(windowState);
Svetoslav8e3feb12014-02-24 13:46:47 -0800249 }
250 return null;
251 }
252
253 public boolean hasCallbacksLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800254 // TODO: support multi-display for windows observer
255 return (mDisplayMagnifiers.size() > 0
Svetoslav8e3feb12014-02-24 13:46:47 -0800256 || mWindowsForAccessibilityObserver != null);
257 }
258
Rhed Jao02655dc2018-10-30 20:44:52 +0800259 public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) {
260 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
261 if (displayMagnifier != null) {
262 displayMagnifier.setForceShowMagnifiableBoundsLocked(show);
263 displayMagnifier.showMagnificationBoundsIfNeeded();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800264 }
265 }
266
Svetoslav8e3feb12014-02-24 13:46:47 -0800267 private static void populateTransformationMatrixLocked(WindowState windowState,
268 Matrix outMatrix) {
Jorim Jaggieb0d3bc2017-12-15 14:56:19 +0100269 windowState.getTransformationMatrix(sTempFloats, outMatrix);
Svetoslav8e3feb12014-02-24 13:46:47 -0800270 }
271
272 /**
273 * This class encapsulates the functionality related to display magnification.
274 */
275 private static final class DisplayMagnifier {
276
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800277 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800278
279 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
280 private static final boolean DEBUG_ROTATION = false;
281 private static final boolean DEBUG_LAYERS = false;
282 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
283 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
284
285 private final Rect mTempRect1 = new Rect();
286 private final Rect mTempRect2 = new Rect();
287
288 private final Region mTempRegion1 = new Region();
289 private final Region mTempRegion2 = new Region();
290 private final Region mTempRegion3 = new Region();
291 private final Region mTempRegion4 = new Region();
292
293 private final Context mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700294 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800295 private final MagnifiedViewport mMagnifedViewport;
296 private final Handler mHandler;
Rhed Jao02655dc2018-10-30 20:44:52 +0800297 private final DisplayContent mDisplayContent;
298 private final Display mDisplay;
Svetoslav8e3feb12014-02-24 13:46:47 -0800299
300 private final MagnificationCallbacks mCallbacks;
301
302 private final long mLongAnimationDuration;
303
Casey Burkhardt74922c62017-02-13 12:43:16 -0800304 private boolean mForceShowMagnifiableBounds = false;
305
Svetoslav8e3feb12014-02-24 13:46:47 -0800306 public DisplayMagnifier(WindowManagerService windowManagerService,
Rhed Jao02655dc2018-10-30 20:44:52 +0800307 DisplayContent displayContent,
308 Display display,
Svetoslav8e3feb12014-02-24 13:46:47 -0800309 MagnificationCallbacks callbacks) {
310 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700311 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800312 mCallbacks = callbacks;
Rhed Jao02655dc2018-10-30 20:44:52 +0800313 mDisplayContent = displayContent;
314 mDisplay = display;
Robert Carre625fcf2017-09-01 12:36:28 -0700315 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslav8e3feb12014-02-24 13:46:47 -0800316 mMagnifedViewport = new MagnifiedViewport();
317 mLongAnimationDuration = mContext.getResources().getInteger(
318 com.android.internal.R.integer.config_longAnimTime);
319 }
320
321 public void setMagnificationSpecLocked(MagnificationSpec spec) {
322 mMagnifedViewport.updateMagnificationSpecLocked(spec);
323 mMagnifedViewport.recomputeBoundsLocked();
Robert Carrb1579c82017-09-05 14:54:47 -0700324
Rhed Jao02655dc2018-10-30 20:44:52 +0800325 mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
Robert Carre625fcf2017-09-01 12:36:28 -0700326 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800327 }
328
Casey Burkhardt74922c62017-02-13 12:43:16 -0800329 public void setForceShowMagnifiableBoundsLocked(boolean show) {
330 mForceShowMagnifiableBounds = show;
331 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
332 }
333
334 public boolean isForceShowingMagnifiableBoundsLocked() {
335 return mForceShowMagnifiableBounds;
336 }
337
Svetoslavf7174e82014-06-12 11:29:35 -0700338 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800339 if (DEBUG_RECTANGLE_REQUESTED) {
340 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
341 }
342 if (!mMagnifedViewport.isMagnifyingLocked()) {
343 return;
344 }
345 Rect magnifiedRegionBounds = mTempRect2;
346 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
347 if (magnifiedRegionBounds.contains(rectangle)) {
348 return;
349 }
350 SomeArgs args = SomeArgs.obtain();
351 args.argi1 = rectangle.left;
352 args.argi2 = rectangle.top;
353 args.argi3 = rectangle.right;
354 args.argi4 = rectangle.bottom;
355 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
356 args).sendToTarget();
357 }
358
359 public void onWindowLayersChangedLocked() {
360 if (DEBUG_LAYERS) {
361 Slog.i(LOG_TAG, "Layers changed.");
362 }
363 mMagnifedViewport.recomputeBoundsLocked();
Robert Carre625fcf2017-09-01 12:36:28 -0700364 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800365 }
366
Andrii Kulian8ee72852017-03-10 10:36:45 -0800367 public void onRotationChangedLocked(DisplayContent displayContent) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800368 if (DEBUG_ROTATION) {
Andrii Kulian8ee72852017-03-10 10:36:45 -0800369 final int rotation = displayContent.getRotation();
370 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
Svetoslav8e3feb12014-02-24 13:46:47 -0800371 + " displayId: " + displayContent.getDisplayId());
372 }
373 mMagnifedViewport.onRotationChangedLocked();
374 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
375 }
376
377 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
378 if (DEBUG_WINDOW_TRANSITIONS) {
379 Slog.i(LOG_TAG, "Window transition: "
380 + AppTransition.appTransitionToString(transition)
381 + " displayId: " + windowState.getDisplayId());
382 }
383 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
384 if (magnifying) {
385 switch (transition) {
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100386 case WindowManager.TRANSIT_ACTIVITY_OPEN:
387 case WindowManager.TRANSIT_TASK_OPEN:
388 case WindowManager.TRANSIT_TASK_TO_FRONT:
389 case WindowManager.TRANSIT_WALLPAPER_OPEN:
390 case WindowManager.TRANSIT_WALLPAPER_CLOSE:
391 case WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800392 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
393 }
394 }
395 }
396 }
397
398 public void onWindowTransitionLocked(WindowState windowState, int transition) {
399 if (DEBUG_WINDOW_TRANSITIONS) {
400 Slog.i(LOG_TAG, "Window transition: "
401 + AppTransition.appTransitionToString(transition)
402 + " displayId: " + windowState.getDisplayId());
403 }
404 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
405 final int type = windowState.mAttrs.type;
406 switch (transition) {
407 case WindowManagerPolicy.TRANSIT_ENTER:
408 case WindowManagerPolicy.TRANSIT_SHOW: {
409 if (!magnifying) {
410 break;
411 }
412 switch (type) {
413 case WindowManager.LayoutParams.TYPE_APPLICATION:
Chong Zhangfea963e2016-08-15 17:14:16 -0700414 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
Svetoslav8e3feb12014-02-24 13:46:47 -0800415 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
416 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
417 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700418 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800419 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
420 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
421 case WindowManager.LayoutParams.TYPE_PHONE:
422 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
423 case WindowManager.LayoutParams.TYPE_TOAST:
424 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800425 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
Svetoslav8e3feb12014-02-24 13:46:47 -0800426 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
427 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
428 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
429 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
430 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500431 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200432 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800433 Rect magnifiedRegionBounds = mTempRect2;
434 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
435 magnifiedRegionBounds);
436 Rect touchableRegionBounds = mTempRect1;
437 windowState.getTouchableRegion(mTempRegion1);
438 mTempRegion1.getBounds(touchableRegionBounds);
439 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
440 mCallbacks.onRectangleOnScreenRequested(
441 touchableRegionBounds.left,
442 touchableRegionBounds.top,
443 touchableRegionBounds.right,
444 touchableRegionBounds.bottom);
445 }
446 } break;
447 } break;
448 }
449 }
450 }
451
452 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
453 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
454 if (spec != null && !spec.isNop()) {
Robert Carrb1579c82017-09-05 14:54:47 -0700455 if (!windowState.shouldMagnify()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800456 return null;
457 }
458 }
459 return spec;
460 }
461
Phil Weaver70439242016-03-10 15:15:49 -0800462 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Phil Weaver53b690b2017-08-14 17:42:39 -0700463 // Make sure we're working with the most current bounds
464 mMagnifedViewport.recomputeBoundsLocked();
Phil Weaver70439242016-03-10 15:15:49 -0800465 mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400466 }
467
Svetoslav8e3feb12014-02-24 13:46:47 -0800468 public void destroyLocked() {
469 mMagnifedViewport.destroyWindow();
470 }
471
Phil Weaver251db072017-03-28 08:35:38 -0700472 // Can be called outside of a surface transaction
473 public void showMagnificationBoundsIfNeeded() {
474 mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
475 .sendToTarget();
476 }
477
Svetoslav8e3feb12014-02-24 13:46:47 -0800478 /** NOTE: This has to be called within a surface transaction. */
479 public void drawMagnifiedRegionBorderIfNeededLocked() {
480 mMagnifedViewport.drawWindowIfNeededLocked();
481 }
482
483 private final class MagnifiedViewport {
484
Svetoslav8e3feb12014-02-24 13:46:47 -0800485 private final SparseArray<WindowState> mTempWindowStates =
486 new SparseArray<WindowState>();
487
488 private final RectF mTempRectF = new RectF();
489
490 private final Point mTempPoint = new Point();
491
492 private final Matrix mTempMatrix = new Matrix();
493
Phil Weaver70439242016-03-10 15:15:49 -0800494 private final Region mMagnificationRegion = new Region();
495 private final Region mOldMagnificationRegion = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800496
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800497 private final Path mCircularPath;
498
Svetoslav8e3feb12014-02-24 13:46:47 -0800499 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
500
501 private final WindowManager mWindowManager;
502
Svetoslav7505e332014-08-22 12:14:28 -0700503 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800504 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700505 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800506
507 private final ViewportWindow mWindow;
508
509 private boolean mFullRedrawNeeded;
Robert Carrb1579c82017-09-05 14:54:47 -0700510 private int mTempLayer = 0;
Svetoslav8e3feb12014-02-24 13:46:47 -0800511
512 public MagnifiedViewport() {
513 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800514 mBorderWidth = mContext.getResources().getDimension(
515 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700516 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
517 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800518 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800519
Adam Powell01f280d2015-05-18 16:07:42 -0700520 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800521 mCircularPath = new Path();
Rhed Jao02655dc2018-10-30 20:44:52 +0800522 mDisplay.getRealSize(mTempPoint);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800523 final int centerXY = mTempPoint.x / 2;
524 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
525 } else {
526 mCircularPath = null;
527 }
528
Svetoslav8e3feb12014-02-24 13:46:47 -0800529 recomputeBoundsLocked();
530 }
531
Phil Weaver70439242016-03-10 15:15:49 -0800532 public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
533 outMagnificationRegion.set(mMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400534 }
535
Svetoslav8e3feb12014-02-24 13:46:47 -0800536 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
537 if (spec != null) {
538 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
539 } else {
540 mMagnificationSpec.clear();
541 }
542 // If this message is pending we are in a rotation animation and do not want
543 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700544 if (!mHandler.hasMessages(
545 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800546 setMagnifiedRegionBorderShownLocked(
547 isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
Svetoslav8e3feb12014-02-24 13:46:47 -0800548 }
549 }
550
551 public void recomputeBoundsLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800552 mDisplay.getRealSize(mTempPoint);
Svetoslav8e3feb12014-02-24 13:46:47 -0800553 final int screenWidth = mTempPoint.x;
554 final int screenHeight = mTempPoint.y;
555
Phil Weaver70439242016-03-10 15:15:49 -0800556 mMagnificationRegion.set(0, 0, 0, 0);
557 final Region availableBounds = mTempRegion1;
558 availableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800559
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800560 if (mCircularPath != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800561 availableBounds.setPath(mCircularPath, availableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800562 }
563
Svetoslav8e3feb12014-02-24 13:46:47 -0800564 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700565 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800566
567 SparseArray<WindowState> visibleWindows = mTempWindowStates;
568 visibleWindows.clear();
569 populateWindowsOnScreenLocked(visibleWindows);
570
571 final int visibleWindowCount = visibleWindows.size();
572 for (int i = visibleWindowCount - 1; i >= 0; i--) {
573 WindowState windowState = visibleWindows.valueAt(i);
Phil Weaverd321075e2017-06-13 09:13:35 -0700574 if ((windowState.mAttrs.type == TYPE_MAGNIFICATION_OVERLAY)
575 || ((windowState.mAttrs.privateFlags
Robert Carr132c9f52017-07-31 17:02:30 -0700576 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800577 continue;
578 }
579
Phil Weaver65c06702016-03-15 15:33:46 -0700580 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800581 Matrix matrix = mTempMatrix;
582 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700583 Region touchableRegion = mTempRegion3;
584 windowState.getTouchableRegion(touchableRegion);
585 Rect touchableFrame = mTempRect1;
586 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800587 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700588 windowFrame.set(touchableFrame);
chaviw492139a2018-07-16 16:07:35 -0700589 windowFrame.offset(-windowState.getFrameLw().left,
590 -windowState.getFrameLw().top);
Phil Weaver65c06702016-03-15 15:33:46 -0700591 matrix.mapRect(windowFrame);
592 Region windowBounds = mTempRegion2;
593 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
594 (int) windowFrame.right, (int) windowFrame.bottom);
595 // Only update new regions
596 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
Phil Weaver70439242016-03-10 15:15:49 -0800597 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
Phil Weaver65c06702016-03-15 15:33:46 -0700598 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
599 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800600
Robert Carrb1579c82017-09-05 14:54:47 -0700601 if (windowState.shouldMagnify()) {
Phil Weaver70439242016-03-10 15:15:49 -0800602 mMagnificationRegion.op(windowBounds, Region.Op.UNION);
603 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800604 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800605 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Phil Weaver70439242016-03-10 15:15:49 -0800606 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800607 }
608
Jackal Guoc2e12c42019-02-27 17:06:33 +0800609 // Count letterbox into nonMagnifiedBounds
610 if (windowState.isLetterboxedForDisplayCutoutLw()) {
611 Region letterboxBounds = getLetterboxBounds(windowState);
612 nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
613 availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
614 }
615
Phil Weaver65c06702016-03-15 15:33:46 -0700616 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800617 Region accountedBounds = mTempRegion2;
Phil Weaver70439242016-03-10 15:15:49 -0800618 accountedBounds.set(mMagnificationRegion);
Svetoslav8e3feb12014-02-24 13:46:47 -0800619 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
620 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
621
622 if (accountedBounds.isRect()) {
623 Rect accountedFrame = mTempRect1;
624 accountedBounds.getBounds(accountedFrame);
625 if (accountedFrame.width() == screenWidth
626 && accountedFrame.height() == screenHeight) {
627 break;
628 }
629 }
630 }
631
632 visibleWindows.clear();
633
Phil Weaver70439242016-03-10 15:15:49 -0800634 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700635 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800636 Region.Op.INTERSECT);
637
Phil Weaver70439242016-03-10 15:15:49 -0800638 final boolean magnifiedChanged =
639 !mOldMagnificationRegion.equals(mMagnificationRegion);
640 if (magnifiedChanged) {
641 mWindow.setBounds(mMagnificationRegion);
642 final Rect dirtyRect = mTempRect1;
643 if (mFullRedrawNeeded) {
644 mFullRedrawNeeded = false;
645 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
646 screenWidth - mDrawBorderInset,
647 screenHeight - mDrawBorderInset);
648 mWindow.invalidate(dirtyRect);
649 } else {
650 final Region dirtyRegion = mTempRegion3;
651 dirtyRegion.set(mMagnificationRegion);
652 dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
653 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
654 dirtyRegion.getBounds(dirtyRect);
655 mWindow.invalidate(dirtyRect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800656 }
657
Phil Weaver70439242016-03-10 15:15:49 -0800658 mOldMagnificationRegion.set(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500659 final SomeArgs args = SomeArgs.obtain();
Phil Weaver70439242016-03-10 15:15:49 -0800660 args.arg1 = Region.obtain(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500661 mHandler.obtainMessage(
Phil Weaver70439242016-03-10 15:15:49 -0800662 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
663 .sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800664 }
665 }
666
Jackal Guoc2e12c42019-02-27 17:06:33 +0800667 private Region getLetterboxBounds(WindowState windowState) {
668 final AppWindowToken appToken = windowState.mAppToken;
669 if (appToken == null) {
670 return new Region();
671 }
672
673 mDisplay.getRealSize(mTempPoint);
674 final Rect letterboxInsets = appToken.getLetterboxInsets();
675 final int screenWidth = mTempPoint.x;
676 final int screenHeight = mTempPoint.y;
677 final Rect nonLetterboxRect = mTempRect1;
678 final Region letterboxBounds = mTempRegion3;
679 nonLetterboxRect.set(0, 0, screenWidth, screenHeight);
680 nonLetterboxRect.inset(letterboxInsets);
681 letterboxBounds.set(0, 0, screenWidth, screenHeight);
682 letterboxBounds.op(nonLetterboxRect, Region.Op.DIFFERENCE);
683 return letterboxBounds;
684 }
685
Svetoslav8e3feb12014-02-24 13:46:47 -0800686 public void onRotationChangedLocked() {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800687 // If we are showing the magnification border, hide it immediately so
Svetoslav8e3feb12014-02-24 13:46:47 -0800688 // the user does not see strange artifacts during rotation. The screenshot
Casey Burkhardt74922c62017-02-13 12:43:16 -0800689 // used for rotation already has the border. After the rotation is complete
Svetoslav8e3feb12014-02-24 13:46:47 -0800690 // we will show the border.
Casey Burkhardt74922c62017-02-13 12:43:16 -0800691 if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800692 setMagnifiedRegionBorderShownLocked(false, false);
693 final long delay = (long) (mLongAnimationDuration
Robert Carre625fcf2017-09-01 12:36:28 -0700694 * mService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800695 Message message = mHandler.obtainMessage(
696 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
697 mHandler.sendMessageDelayed(message, delay);
698 }
699 recomputeBoundsLocked();
700 mWindow.updateSize();
701 }
702
703 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
704 if (shown) {
705 mFullRedrawNeeded = true;
Phil Weaver70439242016-03-10 15:15:49 -0800706 mOldMagnificationRegion.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800707 }
708 mWindow.setShown(shown, animate);
709 }
710
711 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
712 MagnificationSpec spec = mMagnificationSpec;
Phil Weaver70439242016-03-10 15:15:49 -0800713 mMagnificationRegion.getBounds(rect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800714 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
715 rect.scale(1.0f / spec.scale);
716 }
717
718 public boolean isMagnifyingLocked() {
719 return mMagnificationSpec.scale > 1.0f;
720 }
721
722 public MagnificationSpec getMagnificationSpecLocked() {
723 return mMagnificationSpec;
724 }
725
726 /** NOTE: This has to be called within a surface transaction. */
727 public void drawWindowIfNeededLocked() {
728 recomputeBoundsLocked();
729 mWindow.drawIfNeeded();
730 }
731
732 public void destroyWindow() {
733 mWindow.releaseSurface();
734 }
735
736 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Robert Carrb1579c82017-09-05 14:54:47 -0700737 mTempLayer = 0;
Rhed Jao02655dc2018-10-30 20:44:52 +0800738 mDisplayContent.forAllWindows((w) -> {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800739 if (w.isOnScreen() && w.isVisibleLw()
Phil Weaverd6ce7372018-05-18 09:48:01 -0700740 && (w.mAttrs.alpha != 0)
Wale Ogunwaled1880962016-11-08 10:31:59 -0800741 && !w.mWinAnimator.mEnterAnimationPending) {
Robert Carrb1579c82017-09-05 14:54:47 -0700742 mTempLayer++;
743 outWindows.put(mTempLayer, w);
Svetoslav8e3feb12014-02-24 13:46:47 -0800744 }
Wale Ogunwaled1880962016-11-08 10:31:59 -0800745 }, false /* traverseTopToBottom */ );
Svetoslav8e3feb12014-02-24 13:46:47 -0800746 }
747
748 private final class ViewportWindow {
749 private static final String SURFACE_TITLE = "Magnification Overlay";
750
Svetoslav8e3feb12014-02-24 13:46:47 -0800751 private final Region mBounds = new Region();
752 private final Rect mDirtyRect = new Rect();
753 private final Paint mPaint = new Paint();
754
Svetoslav8e3feb12014-02-24 13:46:47 -0800755 private final SurfaceControl mSurfaceControl;
756 private final Surface mSurface = new Surface();
757
Svet Ganovb21df802014-09-01 19:06:33 -0700758 private final AnimationController mAnimationController;
759
Svetoslav8e3feb12014-02-24 13:46:47 -0800760 private boolean mShown;
761 private int mAlpha;
762
763 private boolean mInvalidated;
764
765 public ViewportWindow(Context context) {
766 SurfaceControl surfaceControl = null;
767 try {
Rhed Jao02655dc2018-10-30 20:44:52 +0800768 mDisplay.getRealSize(mTempPoint);
769 surfaceControl = mDisplayContent
770 .makeOverlay()
Robert Carre625fcf2017-09-01 12:36:28 -0700771 .setName(SURFACE_TITLE)
Vishnu Naire86bd982018-11-28 13:23:17 -0800772 .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo
Robert Carre625fcf2017-09-01 12:36:28 -0700773 .setFormat(PixelFormat.TRANSLUCENT)
774 .build();
Svetoslav8e3feb12014-02-24 13:46:47 -0800775 } catch (OutOfResourcesException oore) {
776 /* ignore */
777 }
778 mSurfaceControl = surfaceControl;
Robert Carre625fcf2017-09-01 12:36:28 -0700779 mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
Phil Weaverd321075e2017-06-13 09:13:35 -0700780 TYPE_MAGNIFICATION_OVERLAY)
Svetoslav8e3feb12014-02-24 13:46:47 -0800781 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
782 mSurfaceControl.setPosition(0, 0);
783 mSurface.copyFrom(mSurfaceControl);
784
Svet Ganovb21df802014-09-01 19:06:33 -0700785 mAnimationController = new AnimationController(context,
Robert Carre625fcf2017-09-01 12:36:28 -0700786 mService.mH.getLooper());
Svet Ganovb21df802014-09-01 19:06:33 -0700787
Svetoslav8e3feb12014-02-24 13:46:47 -0800788 TypedValue typedValue = new TypedValue();
789 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
790 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700791 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800792
793 mPaint.setStyle(Paint.Style.STROKE);
794 mPaint.setStrokeWidth(mBorderWidth);
795 mPaint.setColor(borderColor);
796
Svetoslav8e3feb12014-02-24 13:46:47 -0800797 mInvalidated = true;
798 }
799
800 public void setShown(boolean shown, boolean animate) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700801 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800802 if (mShown == shown) {
803 return;
804 }
805 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700806 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800807 if (DEBUG_VIEWPORT_WINDOW) {
808 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
809 }
810 }
811 }
812
813 @SuppressWarnings("unused")
814 // Called reflectively from an animator.
815 public int getAlpha() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700816 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800817 return mAlpha;
818 }
819 }
820
821 public void setAlpha(int alpha) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700822 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800823 if (mAlpha == alpha) {
824 return;
825 }
826 mAlpha = alpha;
827 invalidate(null);
828 if (DEBUG_VIEWPORT_WINDOW) {
829 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
830 }
831 }
832 }
833
834 public void setBounds(Region bounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700835 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800836 if (mBounds.equals(bounds)) {
837 return;
838 }
839 mBounds.set(bounds);
840 invalidate(mDirtyRect);
841 if (DEBUG_VIEWPORT_WINDOW) {
842 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
843 }
844 }
845 }
846
847 public void updateSize() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700848 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800849 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
Vishnu Naire86bd982018-11-28 13:23:17 -0800850 mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y);
Svetoslav8e3feb12014-02-24 13:46:47 -0800851 invalidate(mDirtyRect);
852 }
853 }
854
855 public void invalidate(Rect dirtyRect) {
856 if (dirtyRect != null) {
857 mDirtyRect.set(dirtyRect);
858 } else {
859 mDirtyRect.setEmpty();
860 }
861 mInvalidated = true;
Robert Carre625fcf2017-09-01 12:36:28 -0700862 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800863 }
864
865 /** NOTE: This has to be called within a surface transaction. */
866 public void drawIfNeeded() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700867 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800868 if (!mInvalidated) {
869 return;
870 }
871 mInvalidated = false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800872 if (mAlpha > 0) {
Adrian Roos69364f52018-04-19 18:49:39 +0200873 Canvas canvas = null;
874 try {
875 // Empty dirty rectangle means unspecified.
876 if (mDirtyRect.isEmpty()) {
877 mBounds.getBounds(mDirtyRect);
878 }
879 mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
880 canvas = mSurface.lockCanvas(mDirtyRect);
881 if (DEBUG_VIEWPORT_WINDOW) {
882 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
883 }
884 } catch (IllegalArgumentException iae) {
885 /* ignore */
886 } catch (Surface.OutOfResourcesException oore) {
887 /* ignore */
888 }
889 if (canvas == null) {
890 return;
891 }
892 if (DEBUG_VIEWPORT_WINDOW) {
893 Slog.i(LOG_TAG, "Bounds: " + mBounds);
894 }
895 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
896 mPaint.setAlpha(mAlpha);
897 Path path = mBounds.getBoundaryPath();
898 canvas.drawPath(path, mPaint);
899
900 mSurface.unlockCanvasAndPost(canvas);
Svetoslav8e3feb12014-02-24 13:46:47 -0800901 mSurfaceControl.show();
902 } else {
903 mSurfaceControl.hide();
904 }
905 }
906 }
907
908 public void releaseSurface() {
chaviw9f6171e2019-06-07 16:33:50 -0700909 mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
Svetoslav8e3feb12014-02-24 13:46:47 -0800910 mSurface.release();
911 }
Svet Ganovb21df802014-09-01 19:06:33 -0700912
913 private final class AnimationController extends Handler {
914 private static final String PROPERTY_NAME_ALPHA = "alpha";
915
916 private static final int MIN_ALPHA = 0;
917 private static final int MAX_ALPHA = 255;
918
919 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
920
921 private final ValueAnimator mShowHideFrameAnimator;
922
923 public AnimationController(Context context, Looper looper) {
924 super(looper);
925 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
926 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
927
928 Interpolator interpolator = new DecelerateInterpolator(2.5f);
929 final long longAnimationDuration = context.getResources().getInteger(
930 com.android.internal.R.integer.config_longAnimTime);
931
932 mShowHideFrameAnimator.setInterpolator(interpolator);
933 mShowHideFrameAnimator.setDuration(longAnimationDuration);
934 }
935
936 public void onFrameShownStateChanged(boolean shown, boolean animate) {
937 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
938 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
939 }
940
941 @Override
942 public void handleMessage(Message message) {
943 switch (message.what) {
944 case MSG_FRAME_SHOWN_STATE_CHANGED: {
945 final boolean shown = message.arg1 == 1;
946 final boolean animate = message.arg2 == 1;
947
948 if (animate) {
949 if (mShowHideFrameAnimator.isRunning()) {
950 mShowHideFrameAnimator.reverse();
951 } else {
952 if (shown) {
953 mShowHideFrameAnimator.start();
954 } else {
955 mShowHideFrameAnimator.reverse();
956 }
957 }
958 } else {
959 mShowHideFrameAnimator.cancel();
960 if (shown) {
961 setAlpha(MAX_ALPHA);
962 } else {
963 setAlpha(MIN_ALPHA);
964 }
965 }
966 } break;
967 }
968 }
969 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800970 }
971 }
972
973 private class MyHandler extends Handler {
Phil Weaver70439242016-03-10 15:15:49 -0800974 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -0800975 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
976 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
977 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
978 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
979
980 public MyHandler(Looper looper) {
981 super(looper);
982 }
983
984 @Override
985 public void handleMessage(Message message) {
986 switch (message.what) {
Phil Weaver70439242016-03-10 15:15:49 -0800987 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500988 final SomeArgs args = (SomeArgs) message.obj;
989 final Region magnifiedBounds = (Region) args.arg1;
Phil Weaver70439242016-03-10 15:15:49 -0800990 mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500991 magnifiedBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800992 } break;
993
994 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
995 SomeArgs args = (SomeArgs) message.obj;
996 final int left = args.argi1;
997 final int top = args.argi2;
998 final int right = args.argi3;
999 final int bottom = args.argi4;
1000 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
1001 args.recycle();
1002 } break;
1003
1004 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
1005 mCallbacks.onUserContextChanged();
1006 } break;
1007
1008 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
1009 final int rotation = message.arg1;
1010 mCallbacks.onRotationChanged(rotation);
1011 } break;
1012
1013 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001014 synchronized (mService.mGlobalLock) {
Casey Burkhardt74922c62017-02-13 12:43:16 -08001015 if (mMagnifedViewport.isMagnifyingLocked()
1016 || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001017 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
Robert Carre625fcf2017-09-01 12:36:28 -07001018 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -08001019 }
1020 }
1021 } break;
1022 }
1023 }
1024 }
1025 }
1026
1027 /**
1028 * This class encapsulates the functionality related to computing the windows
1029 * reported for accessibility purposes. These windows are all windows a sighted
1030 * user can see on the screen.
1031 */
1032 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -08001033 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
1034 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -08001035
1036 private static final boolean DEBUG = false;
1037
Jackal Guo28dce102019-05-28 14:25:17 +08001038 private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001039
Jackal Guo28dce102019-05-28 14:25:17 +08001040 private final Set<IBinder> mTempBinderSet = new ArraySet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001041
1042 private final RectF mTempRectF = new RectF();
1043
1044 private final Matrix mTempMatrix = new Matrix();
1045
1046 private final Point mTempPoint = new Point();
1047
1048 private final Rect mTempRect = new Rect();
1049
1050 private final Region mTempRegion = new Region();
1051
1052 private final Region mTempRegion1 = new Region();
1053
1054 private final Context mContext;
1055
Robert Carre625fcf2017-09-01 12:36:28 -07001056 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001057
1058 private final Handler mHandler;
1059
1060 private final WindowsForAccessibilityCallback mCallback;
1061
Svetoslavf7174e82014-06-12 11:29:35 -07001062 private final long mRecurringAccessibilityEventsIntervalMillis;
1063
Svetoslav8e3feb12014-02-24 13:46:47 -08001064 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
1065 WindowsForAccessibilityCallback callback) {
1066 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -07001067 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001068 mCallback = callback;
Robert Carre625fcf2017-09-01 12:36:28 -07001069 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -07001070 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1071 .getSendRecurringAccessibilityEventsInterval();
Phil Weaverc72faad2018-07-24 10:53:01 -07001072 computeChangedWindows(true);
Svetoslav8e3feb12014-02-24 13:46:47 -08001073 }
1074
Phil Weaverc72faad2018-07-24 10:53:01 -07001075 public void performComputeChangedWindowsNotLocked(boolean forceSend) {
Svetoslav3a0d8782014-12-04 12:50:11 -08001076 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
Phil Weaverc72faad2018-07-24 10:53:01 -07001077 computeChangedWindows(forceSend);
Svetoslav3a0d8782014-12-04 12:50:11 -08001078 }
1079
Svetoslavf7174e82014-06-12 11:29:35 -07001080 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -08001081 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001082 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1083 mRecurringAccessibilityEventsIntervalMillis);
1084 }
1085 }
1086
Phil Weaverc72faad2018-07-24 10:53:01 -07001087 /**
Jackal Guoc43a0a62019-04-23 09:15:14 +08001088 * Check if windows have changed, and send them to the accessibility subsystem if they have.
Phil Weaverc72faad2018-07-24 10:53:01 -07001089 *
1090 * @param forceSend Send the windows the accessibility even if they haven't changed.
1091 */
1092 public void computeChangedWindows(boolean forceSend) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001093 if (DEBUG) {
1094 Slog.i(LOG_TAG, "computeChangedWindows()");
1095 }
1096
Jackal Guo28dce102019-05-28 14:25:17 +08001097 List<WindowInfo> windows = new ArrayList<>();
Svetoslav3a0d8782014-12-04 12:50:11 -08001098
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001099 synchronized (mService.mGlobalLock) {
Svetoslavf7174e82014-06-12 11:29:35 -07001100 // Do not send the windows if there is no current focus as
1101 // the window manager is still looking for where to put it.
1102 // We will do the work when we get a focus change callback.
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001103 // TODO(b/112273690): Support multiple displays
Jackal Guoc43a0a62019-04-23 09:15:14 +08001104 if (!isCurrentFocusWindowOnDefaultDisplay()) {
Svetoslavf7174e82014-06-12 11:29:35 -07001105 return;
1106 }
1107
Svetoslav8e3feb12014-02-24 13:46:47 -08001108 WindowManager windowManager = (WindowManager)
1109 mContext.getSystemService(Context.WINDOW_SERVICE);
1110 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1111 final int screenWidth = mTempPoint.x;
1112 final int screenHeight = mTempPoint.y;
1113
1114 Region unaccountedSpace = mTempRegion;
1115 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1116
Wale Ogunwalef7cab102016-10-25 15:25:14 -07001117 final SparseArray<WindowState> visibleWindows = mTempWindowStates;
Svetoslav8e3feb12014-02-24 13:46:47 -08001118 populateVisibleWindowsOnScreenLocked(visibleWindows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001119 Set<IBinder> addedWindows = mTempBinderSet;
1120 addedWindows.clear();
1121
Svetoslavf7174e82014-06-12 11:29:35 -07001122 boolean focusedWindowAdded = false;
1123
Svetoslav8e3feb12014-02-24 13:46:47 -08001124 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001125 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001126
1127 // Iterate until we figure out what is touchable for the entire screen.
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001128 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001129 final WindowState windowState = visibleWindows.valueAt(i);
Jackal Guof3823712019-05-20 10:16:06 +08001130 final Region regionInScreen = new Region();
1131 computeWindowRegionInScreen(windowState, regionInScreen);
Allen Hairf20ac2c2016-02-11 17:42:59 -08001132
Jackal Guof3823712019-05-20 10:16:06 +08001133 if (windowMattersToAccessibility(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001134 skipRemainingWindowsForTasks)) {
Jackal Guof3823712019-05-20 10:16:06 +08001135 addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows);
1136 updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001137 skipRemainingWindowsForTasks);
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001138 focusedWindowAdded |= windowState.isFocused();
1139 }
1140
1141 if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
1142 break;
Svetoslavf7174e82014-06-12 11:29:35 -07001143 }
1144 }
1145
Svetoslav8e3feb12014-02-24 13:46:47 -08001146 // Remove child/parent references to windows that were not added.
1147 final int windowCount = windows.size();
1148 for (int i = 0; i < windowCount; i++) {
1149 WindowInfo window = windows.get(i);
1150 if (!addedWindows.contains(window.parentToken)) {
1151 window.parentToken = null;
1152 }
1153 if (window.childTokens != null) {
1154 final int childTokenCount = window.childTokens.size();
1155 for (int j = childTokenCount - 1; j >= 0; j--) {
1156 if (!addedWindows.contains(window.childTokens.get(j))) {
1157 window.childTokens.remove(j);
1158 }
1159 }
1160 // Leave the child token list if empty.
1161 }
1162 }
1163
1164 visibleWindows.clear();
1165 addedWindows.clear();
Svetoslav8e3feb12014-02-24 13:46:47 -08001166 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001167
Jackal Guo28dce102019-05-28 14:25:17 +08001168 mCallback.onWindowsForAccessibilityChanged(forceSend, windows);
Svetoslav3a0d8782014-12-04 12:50:11 -08001169
1170 // Recycle the windows as we do not need them.
1171 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001172 }
1173
Jackal Guof3823712019-05-20 10:16:06 +08001174 private boolean windowMattersToAccessibility(WindowState windowState,
1175 Region regionInScreen, Region unaccountedSpace,
1176 HashSet<Integer> skipRemainingWindowsForTasks) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001177 if (windowState.isFocused()) {
1178 return true;
1179 }
1180
1181 // If the window is part of a task that we're finished with - ignore.
1182 final Task task = windowState.getTask();
1183 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1184 return false;
1185 }
1186
1187 // Ignore non-touchable windows, except the split-screen divider, which is
1188 // occasionally non-touchable but still useful for identifying split-screen
1189 // mode.
1190 if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
1191 && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
1192 return false;
1193 }
1194
1195 // If the window is completely covered by other windows - ignore.
Jackal Guof3823712019-05-20 10:16:06 +08001196 if (unaccountedSpace.quickReject(regionInScreen)) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001197 return false;
1198 }
1199
1200 // Add windows of certain types not covered by modal windows.
1201 if (isReportedWindowType(windowState.mAttrs.type)) {
1202 return true;
1203 }
1204
1205 return false;
1206 }
1207
Jackal Guof3823712019-05-20 10:16:06 +08001208 private void updateUnaccountedSpace(WindowState windowState, Region regionInScreen,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001209 Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
1210 if (windowState.mAttrs.type
1211 != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1212
1213 // Account for the space this window takes if the window
1214 // is not an accessibility overlay which does not change
1215 // the reported windows.
Jackal Guof3823712019-05-20 10:16:06 +08001216 unaccountedSpace.op(regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001217 Region.Op.REVERSE_DIFFERENCE);
1218
1219 // If a window is modal it prevents other windows from being touched
1220 if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1221 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Jackal Guof3823712019-05-20 10:16:06 +08001222 if (!windowState.hasTapExcludeRegion()) {
1223 // Account for all space in the task, whether the windows in it are
1224 // touchable or not. The modal window blocks all touches from the task's
1225 // area.
1226 unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
1227 Region.Op.REVERSE_DIFFERENCE);
1228 } else {
1229 // If a window has tap exclude region, we need to account it.
1230 final Region displayRegion = new Region(windowState.getDisplayFrameLw());
1231 final Region tapExcludeRegion = new Region();
1232 windowState.amendTapExcludeRegion(tapExcludeRegion);
1233 displayRegion.op(tapExcludeRegion, displayRegion,
1234 Region.Op.REVERSE_DIFFERENCE);
1235 unaccountedSpace.op(displayRegion, unaccountedSpace,
1236 Region.Op.REVERSE_DIFFERENCE);
1237 }
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001238
1239 final Task task = windowState.getTask();
1240 if (task != null) {
1241 // If the window is associated with a particular task, we can skip the
1242 // rest of the windows for that task.
1243 skipRemainingWindowsForTasks.add(task.mTaskId);
Jackal Guof3823712019-05-20 10:16:06 +08001244 } else if (!windowState.hasTapExcludeRegion()) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001245 // If the window is not associated with a particular task, then it is
Jackal Guof3823712019-05-20 10:16:06 +08001246 // globally modal. In this case we can skip all remaining windows when
1247 // it doesn't has tap exclude region.
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001248 unaccountedSpace.setEmpty();
1249 }
1250 }
1251 }
1252 }
1253
Jackal Guof3823712019-05-20 10:16:06 +08001254 private void computeWindowRegionInScreen(WindowState windowState, Region outRegion) {
Svetoslavf7174e82014-06-12 11:29:35 -07001255 // Get the touchable frame.
1256 Region touchableRegion = mTempRegion1;
1257 windowState.getTouchableRegion(touchableRegion);
Svetoslavf7174e82014-06-12 11:29:35 -07001258
1259 // Map the frame to get what appears on the screen.
1260 Matrix matrix = mTempMatrix;
1261 populateTransformationMatrixLocked(windowState, matrix);
Svetoslavf7174e82014-06-12 11:29:35 -07001262
Jackal Guof3823712019-05-20 10:16:06 +08001263 forEachRect(touchableRegion, rect -> {
1264 // Move to origin as all transforms are captured by the matrix.
1265 RectF windowFrame = mTempRectF;
1266 windowFrame.set(rect);
1267 windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
1268
1269 matrix.mapRect(windowFrame);
1270
1271 // Union all rects.
1272 outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
1273 (int) windowFrame.right, (int) windowFrame.bottom));
1274 });
Svetoslavf7174e82014-06-12 11:29:35 -07001275 }
1276
Jackal Guof3823712019-05-20 10:16:06 +08001277 private static void addPopulatedWindowInfo(WindowState windowState, Region regionInScreen,
Eugene Susla18e7fc112018-03-16 14:35:31 -07001278 List<WindowInfo> out, Set<IBinder> tokenOut) {
Wale Ogunwaleadde52e2016-07-16 13:11:55 -07001279 final WindowInfo window = windowState.getWindowInfo();
Jackal Guof3823712019-05-20 10:16:06 +08001280 window.regionInScreen.set(regionInScreen);
Eugene Susla18e7fc112018-03-16 14:35:31 -07001281 window.layer = tokenOut.size();
1282 out.add(window);
1283 tokenOut.add(window.token);
Svetoslavf7174e82014-06-12 11:29:35 -07001284 }
1285
Svetoslav3a0d8782014-12-04 12:50:11 -08001286 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001287 final int windowCount = windows.size();
1288 for (int i = windowCount - 1; i >= 0; i--) {
1289 windows.remove(i).recycle();
1290 }
1291 }
1292
1293 private static boolean isReportedWindowType(int windowType) {
Jorim Jaggi73294b62016-10-26 18:02:36 -07001294 return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
Svetoslav8e3feb12014-02-24 13:46:47 -08001295 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1296 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1297 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001298 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001299 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Phil Weaverd321075e2017-06-13 09:13:35 -07001300 && windowType != TYPE_MAGNIFICATION_OVERLAY
Svetoslav8e3feb12014-02-24 13:46:47 -08001301 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1302 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1303 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1304 }
1305
1306 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001307 final List<WindowState> tempWindowStatesList = new ArrayList<>();
Robert Carre625fcf2017-09-01 12:36:28 -07001308 final DisplayContent dc = mService.getDefaultDisplayContentLocked();
Jackal Guof3823712019-05-20 10:16:06 +08001309 dc.forAllWindows(w -> {
Wale Ogunwaled1880962016-11-08 10:31:59 -08001310 if (w.isVisibleLw()) {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001311 tempWindowStatesList.add(w);
Svetoslav8e3feb12014-02-24 13:46:47 -08001312 }
Tiger Huangd8ec9382019-04-18 14:35:09 -07001313 }, false /* traverseTopToBottom */);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001314 // Insert the re-parented windows in another display on top of their parents in
1315 // default display.
Tiger Huangd8ec9382019-04-18 14:35:09 -07001316 mService.mRoot.forAllWindows(w -> {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001317 final WindowState parentWindow = findRootDisplayParentWindow(w);
1318 if (parentWindow == null) {
1319 return;
Tiger Huangd8ec9382019-04-18 14:35:09 -07001320 }
Jackal Guoc43a0a62019-04-23 09:15:14 +08001321
Jackal Guoc43a0a62019-04-23 09:15:14 +08001322 if (w.isVisibleLw() && parentWindow.getDisplayContent().isDefaultDisplay
Jackal Guoc43a0a62019-04-23 09:15:14 +08001323 && tempWindowStatesList.contains(parentWindow)) {
Jackal Guof3823712019-05-20 10:16:06 +08001324 tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001325 }
Jackal Guof3823712019-05-20 10:16:06 +08001326 }, false /* traverseTopToBottom */);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001327 for (int i = 0; i < tempWindowStatesList.size(); i++) {
1328 outWindows.put(i, tempWindowStatesList.get(i));
1329 }
Tiger Huangd8ec9382019-04-18 14:35:09 -07001330 }
1331
1332 private WindowState findRootDisplayParentWindow(WindowState win) {
1333 WindowState displayParentWindow = win.getDisplayContent().getParentWindow();
1334 if (displayParentWindow == null) {
1335 return null;
1336 }
1337 WindowState candidate = displayParentWindow;
1338 while (candidate != null) {
1339 displayParentWindow = candidate;
1340 candidate = displayParentWindow.getDisplayContent().getParentWindow();
1341 }
1342 return displayParentWindow;
Svetoslav8e3feb12014-02-24 13:46:47 -08001343 }
1344
Jackal Guoc43a0a62019-04-23 09:15:14 +08001345 private boolean isCurrentFocusWindowOnDefaultDisplay() {
1346 final WindowState focusedWindow =
1347 mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
1348 if (focusedWindow == null) {
1349 return false;
1350 }
1351
1352 final WindowState rootDisplayParentWindow = findRootDisplayParentWindow(focusedWindow);
1353 if (!focusedWindow.isDefaultDisplay()
1354 && (rootDisplayParentWindow == null
1355 || !rootDisplayParentWindow.isDefaultDisplay())) {
1356 return false;
1357 }
1358
1359 return true;
1360 }
1361
Svetoslav8e3feb12014-02-24 13:46:47 -08001362 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001363 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001364
1365 public MyHandler(Looper looper) {
1366 super(looper, null, false);
1367 }
1368
1369 @Override
1370 @SuppressWarnings("unchecked")
1371 public void handleMessage(Message message) {
1372 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001373 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
Phil Weaverc72faad2018-07-24 10:53:01 -07001374 computeChangedWindows(false);
Svetoslavf7174e82014-06-12 11:29:35 -07001375 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001376 }
1377 }
1378 }
1379 }
1380}