blob: 30a3aef01fdb0dbb1d24a14303a8198237d935f3 [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
Jacky Kaof93252b2019-07-18 15:19:52 +080088 private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
89 new SparseArray<>();
Svetoslav8e3feb12014-02-24 13:46:47 -080090
Rhed Jao02655dc2018-10-30 20:44:52 +080091 public boolean setMagnificationCallbacksLocked(int displayId,
92 MagnificationCallbacks callbacks) {
93 boolean result = false;
Svetoslav8e3feb12014-02-24 13:46:47 -080094 if (callbacks != null) {
Rhed Jao02655dc2018-10-30 20:44:52 +080095 if (mDisplayMagnifiers.get(displayId) != null) {
Svetoslav8e3feb12014-02-24 13:46:47 -080096 throw new IllegalStateException("Magnification callbacks already set!");
97 }
Rhed Jao02655dc2018-10-30 20:44:52 +080098 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
99 if (dc != null) {
100 final Display display = dc.getDisplay();
101 if (display != null && display.getType() != Display.TYPE_OVERLAY) {
102 mDisplayMagnifiers.put(displayId, new DisplayMagnifier(
103 mService, dc, display, callbacks));
104 result = true;
105 }
106 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800107 } else {
Rhed Jao02655dc2018-10-30 20:44:52 +0800108 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
109 if (displayMagnifier == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800110 throw new IllegalStateException("Magnification callbacks already cleared!");
111 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800112 displayMagnifier.destroyLocked();
113 mDisplayMagnifiers.remove(displayId);
114 result = true;
Svetoslav8e3feb12014-02-24 13:46:47 -0800115 }
Rhed Jao02655dc2018-10-30 20:44:52 +0800116 return result;
Svetoslav8e3feb12014-02-24 13:46:47 -0800117 }
118
Jacky Kaof93252b2019-07-18 15:19:52 +0800119 public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
120 WindowsForAccessibilityCallback callback) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800121 if (callback != null) {
Jacky Kaof93252b2019-07-18 15:19:52 +0800122 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
123 if (dc == null) {
124 return false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800125 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800126
Jacky Kaof93252b2019-07-18 15:19:52 +0800127 if (mWindowsForAccessibilityObserver.get(displayId) != null) {
Jacky Kao81167402019-08-22 12:05:34 +0800128 final Display display = dc.getDisplay();
Jacky Kaof93252b2019-07-18 15:19:52 +0800129 if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
130 // The window observer of this embedded display had been set from
Jacky Kao81167402019-08-22 12:05:34 +0800131 // window manager after setting its parent window.
Jacky Kaof93252b2019-07-18 15:19:52 +0800132 return true;
133 } else {
134 throw new IllegalStateException(
135 "Windows for accessibility callback of display "
136 + displayId + " already set!");
137 }
138 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800139 mWindowsForAccessibilityObserver.put(displayId,
140 new WindowsForAccessibilityObserver(mService, displayId, callback));
Svetoslav8e3feb12014-02-24 13:46:47 -0800141 } else {
Jacky Kaof93252b2019-07-18 15:19:52 +0800142 final WindowsForAccessibilityObserver windowsForA11yObserver =
143 mWindowsForAccessibilityObserver.get(displayId);
144 if (windowsForA11yObserver == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800145 throw new IllegalStateException(
Jacky Kaof93252b2019-07-18 15:19:52 +0800146 "Windows for accessibility callback of display " + displayId
147 + " already cleared!");
Svetoslav8e3feb12014-02-24 13:46:47 -0800148 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800149 mWindowsForAccessibilityObserver.remove(displayId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800150 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800151 return true;
Svetoslav8e3feb12014-02-24 13:46:47 -0800152 }
153
Jacky Kaof93252b2019-07-18 15:19:52 +0800154 public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) {
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700155 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700156 synchronized (mService) {
Jacky Kaof93252b2019-07-18 15:19:52 +0800157 final WindowsForAccessibilityObserver windowsForA11yObserver =
158 mWindowsForAccessibilityObserver.get(displayId);
159 if (windowsForA11yObserver != null) {
160 observer = windowsForA11yObserver;
161 }
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700162 }
163 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700164 observer.performComputeChangedWindowsNotLocked(forceSend);
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700165 }
166 }
167
Rhed Jao02655dc2018-10-30 20:44:52 +0800168 public void setMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
169 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
170 if (displayMagnifier != null) {
171 displayMagnifier.setMagnificationSpecLocked(spec);
Svetoslav8e3feb12014-02-24 13:46:47 -0800172 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800173 final WindowsForAccessibilityObserver windowsForA11yObserver =
174 mWindowsForAccessibilityObserver.get(displayId);
175 if (windowsForA11yObserver != null) {
176 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800177 }
178 }
179
Rhed Jao02655dc2018-10-30 20:44:52 +0800180 public void getMagnificationRegionLocked(int displayId, Region outMagnificationRegion) {
181 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
182 if (displayMagnifier != null) {
183 displayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400184 }
185 }
186
Rhed Jao02655dc2018-10-30 20:44:52 +0800187 public void onRectangleOnScreenRequestedLocked(int displayId, Rect rectangle) {
188 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
189 if (displayMagnifier != null) {
190 displayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800191 }
192 // Not relevant for the window observer.
193 }
194
Rhed Jao02655dc2018-10-30 20:44:52 +0800195 public void onWindowLayersChangedLocked(int displayId) {
196 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
197 if (displayMagnifier != null) {
198 displayMagnifier.onWindowLayersChangedLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800199 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800200 final WindowsForAccessibilityObserver windowsForA11yObserver =
201 mWindowsForAccessibilityObserver.get(displayId);
202 if (windowsForA11yObserver != null) {
203 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800204 }
205 }
206
Andrii Kulian8ee72852017-03-10 10:36:45 -0800207 public void onRotationChangedLocked(DisplayContent displayContent) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800208 final int displayId = displayContent.getDisplayId();
209 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
210 if (displayMagnifier != null) {
211 displayMagnifier.onRotationChangedLocked(displayContent);
Svetoslav8e3feb12014-02-24 13:46:47 -0800212 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800213 final WindowsForAccessibilityObserver windowsForA11yObserver =
214 mWindowsForAccessibilityObserver.get(displayId);
215 if (windowsForA11yObserver != null) {
216 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800217 }
218 }
219
220 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800221 final int displayId = windowState.getDisplayId();
222 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
223 if (displayMagnifier != null) {
224 displayMagnifier.onAppWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800225 }
226 // Not relevant for the window observer.
227 }
228
229 public void onWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800230 final int displayId = windowState.getDisplayId();
231 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
232 if (displayMagnifier != null) {
233 displayMagnifier.onWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800234 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800235 final WindowsForAccessibilityObserver windowsForA11yObserver =
236 mWindowsForAccessibilityObserver.get(displayId);
237 if (windowsForA11yObserver != null) {
238 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800239 }
240 }
241
Jacky Kaof93252b2019-07-18 15:19:52 +0800242 public void onWindowFocusChangedNotLocked(int displayId) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800243 // Not relevant for the display magnifier.
244
Svetoslav3a0d8782014-12-04 12:50:11 -0800245 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700246 synchronized (mService) {
Jacky Kaof93252b2019-07-18 15:19:52 +0800247 final WindowsForAccessibilityObserver windowsForA11yObserver =
248 mWindowsForAccessibilityObserver.get(displayId);
249 if (windowsForA11yObserver != null) {
250 observer = windowsForA11yObserver;
251 }
Svetoslav3a0d8782014-12-04 12:50:11 -0800252 }
253 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700254 observer.performComputeChangedWindowsNotLocked(false);
Svetoslav8e3feb12014-02-24 13:46:47 -0800255 }
256 }
257
Jacky Kaof93252b2019-07-18 15:19:52 +0800258 public void onSomeWindowResizedOrMovedLocked(int displayId) {
Svetoslav4604abc2014-06-10 18:59:30 -0700259 // Not relevant for the display magnifier.
260
Jacky Kaof93252b2019-07-18 15:19:52 +0800261 final WindowsForAccessibilityObserver windowsForA11yObserver =
262 mWindowsForAccessibilityObserver.get(displayId);
263 if (windowsForA11yObserver != null) {
264 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700265 }
266 }
267
Svetoslav8e3feb12014-02-24 13:46:47 -0800268 /** NOTE: This has to be called within a surface transaction. */
Rhed Jao02655dc2018-10-30 20:44:52 +0800269 public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) {
270 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
271 if (displayMagnifier != null) {
272 displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800273 }
274 // Not relevant for the window observer.
275 }
276
277 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800278 final int displayId = windowState.getDisplayId();
279 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
280 if (displayMagnifier != null) {
281 return displayMagnifier.getMagnificationSpecForWindowLocked(windowState);
Svetoslav8e3feb12014-02-24 13:46:47 -0800282 }
283 return null;
284 }
285
286 public boolean hasCallbacksLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800287 return (mDisplayMagnifiers.size() > 0
Jacky Kao81167402019-08-22 12:05:34 +0800288 || mWindowsForAccessibilityObserver.size() > 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800289 }
290
Rhed Jao02655dc2018-10-30 20:44:52 +0800291 public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) {
292 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
293 if (displayMagnifier != null) {
294 displayMagnifier.setForceShowMagnifiableBoundsLocked(show);
295 displayMagnifier.showMagnificationBoundsIfNeeded();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800296 }
297 }
298
Jacky Kaof93252b2019-07-18 15:19:52 +0800299 public void handleWindowObserverOfEmbeddedDisplayLocked(int embeddedDisplayId,
300 WindowState parentWindow) {
301 if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
302 return;
303 }
304 // Finds the parent display of this embedded display
305 final int parentDisplayId;
306 WindowState candidate = parentWindow;
307 while (candidate != null) {
308 parentWindow = candidate;
309 candidate = parentWindow.getDisplayContent().getParentWindow();
310 }
311 parentDisplayId = parentWindow.getDisplayId();
312 // Uses the observer of parent display
313 final WindowsForAccessibilityObserver windowsForA11yObserver =
314 mWindowsForAccessibilityObserver.get(parentDisplayId);
315
316 if (windowsForA11yObserver != null) {
317 // Replaces the observer of embedded display to the one of parent display
318 mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
319 }
320 }
321
Svetoslav8e3feb12014-02-24 13:46:47 -0800322 private static void populateTransformationMatrixLocked(WindowState windowState,
323 Matrix outMatrix) {
Jorim Jaggieb0d3bc2017-12-15 14:56:19 +0100324 windowState.getTransformationMatrix(sTempFloats, outMatrix);
Svetoslav8e3feb12014-02-24 13:46:47 -0800325 }
326
327 /**
328 * This class encapsulates the functionality related to display magnification.
329 */
330 private static final class DisplayMagnifier {
331
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800332 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800333
334 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
335 private static final boolean DEBUG_ROTATION = false;
336 private static final boolean DEBUG_LAYERS = false;
337 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
338 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
339
340 private final Rect mTempRect1 = new Rect();
341 private final Rect mTempRect2 = new Rect();
342
343 private final Region mTempRegion1 = new Region();
344 private final Region mTempRegion2 = new Region();
345 private final Region mTempRegion3 = new Region();
346 private final Region mTempRegion4 = new Region();
347
348 private final Context mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700349 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800350 private final MagnifiedViewport mMagnifedViewport;
351 private final Handler mHandler;
Rhed Jao02655dc2018-10-30 20:44:52 +0800352 private final DisplayContent mDisplayContent;
353 private final Display mDisplay;
Svetoslav8e3feb12014-02-24 13:46:47 -0800354
355 private final MagnificationCallbacks mCallbacks;
356
357 private final long mLongAnimationDuration;
358
Casey Burkhardt74922c62017-02-13 12:43:16 -0800359 private boolean mForceShowMagnifiableBounds = false;
360
Svetoslav8e3feb12014-02-24 13:46:47 -0800361 public DisplayMagnifier(WindowManagerService windowManagerService,
Rhed Jao02655dc2018-10-30 20:44:52 +0800362 DisplayContent displayContent,
363 Display display,
Svetoslav8e3feb12014-02-24 13:46:47 -0800364 MagnificationCallbacks callbacks) {
365 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700366 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800367 mCallbacks = callbacks;
Rhed Jao02655dc2018-10-30 20:44:52 +0800368 mDisplayContent = displayContent;
369 mDisplay = display;
Robert Carre625fcf2017-09-01 12:36:28 -0700370 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslav8e3feb12014-02-24 13:46:47 -0800371 mMagnifedViewport = new MagnifiedViewport();
372 mLongAnimationDuration = mContext.getResources().getInteger(
373 com.android.internal.R.integer.config_longAnimTime);
374 }
375
376 public void setMagnificationSpecLocked(MagnificationSpec spec) {
377 mMagnifedViewport.updateMagnificationSpecLocked(spec);
378 mMagnifedViewport.recomputeBoundsLocked();
Robert Carrb1579c82017-09-05 14:54:47 -0700379
Rhed Jao02655dc2018-10-30 20:44:52 +0800380 mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
Robert Carre625fcf2017-09-01 12:36:28 -0700381 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800382 }
383
Casey Burkhardt74922c62017-02-13 12:43:16 -0800384 public void setForceShowMagnifiableBoundsLocked(boolean show) {
385 mForceShowMagnifiableBounds = show;
386 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
387 }
388
389 public boolean isForceShowingMagnifiableBoundsLocked() {
390 return mForceShowMagnifiableBounds;
391 }
392
Svetoslavf7174e82014-06-12 11:29:35 -0700393 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800394 if (DEBUG_RECTANGLE_REQUESTED) {
395 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
396 }
397 if (!mMagnifedViewport.isMagnifyingLocked()) {
398 return;
399 }
400 Rect magnifiedRegionBounds = mTempRect2;
401 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
402 if (magnifiedRegionBounds.contains(rectangle)) {
403 return;
404 }
405 SomeArgs args = SomeArgs.obtain();
406 args.argi1 = rectangle.left;
407 args.argi2 = rectangle.top;
408 args.argi3 = rectangle.right;
409 args.argi4 = rectangle.bottom;
410 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
411 args).sendToTarget();
412 }
413
414 public void onWindowLayersChangedLocked() {
415 if (DEBUG_LAYERS) {
416 Slog.i(LOG_TAG, "Layers changed.");
417 }
418 mMagnifedViewport.recomputeBoundsLocked();
Robert Carre625fcf2017-09-01 12:36:28 -0700419 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800420 }
421
Andrii Kulian8ee72852017-03-10 10:36:45 -0800422 public void onRotationChangedLocked(DisplayContent displayContent) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800423 if (DEBUG_ROTATION) {
Andrii Kulian8ee72852017-03-10 10:36:45 -0800424 final int rotation = displayContent.getRotation();
425 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
Svetoslav8e3feb12014-02-24 13:46:47 -0800426 + " displayId: " + displayContent.getDisplayId());
427 }
428 mMagnifedViewport.onRotationChangedLocked();
429 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
430 }
431
432 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
433 if (DEBUG_WINDOW_TRANSITIONS) {
434 Slog.i(LOG_TAG, "Window transition: "
435 + AppTransition.appTransitionToString(transition)
436 + " displayId: " + windowState.getDisplayId());
437 }
438 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
439 if (magnifying) {
440 switch (transition) {
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100441 case WindowManager.TRANSIT_ACTIVITY_OPEN:
442 case WindowManager.TRANSIT_TASK_OPEN:
443 case WindowManager.TRANSIT_TASK_TO_FRONT:
444 case WindowManager.TRANSIT_WALLPAPER_OPEN:
445 case WindowManager.TRANSIT_WALLPAPER_CLOSE:
446 case WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800447 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
448 }
449 }
450 }
451 }
452
453 public void onWindowTransitionLocked(WindowState windowState, int transition) {
454 if (DEBUG_WINDOW_TRANSITIONS) {
455 Slog.i(LOG_TAG, "Window transition: "
456 + AppTransition.appTransitionToString(transition)
457 + " displayId: " + windowState.getDisplayId());
458 }
459 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
460 final int type = windowState.mAttrs.type;
461 switch (transition) {
462 case WindowManagerPolicy.TRANSIT_ENTER:
463 case WindowManagerPolicy.TRANSIT_SHOW: {
464 if (!magnifying) {
465 break;
466 }
467 switch (type) {
468 case WindowManager.LayoutParams.TYPE_APPLICATION:
Chong Zhangfea963e2016-08-15 17:14:16 -0700469 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
Svetoslav8e3feb12014-02-24 13:46:47 -0800470 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
471 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
472 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700473 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800474 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
475 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
476 case WindowManager.LayoutParams.TYPE_PHONE:
477 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
478 case WindowManager.LayoutParams.TYPE_TOAST:
479 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800480 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
Svetoslav8e3feb12014-02-24 13:46:47 -0800481 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
482 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
483 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
484 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
485 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500486 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200487 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800488 Rect magnifiedRegionBounds = mTempRect2;
489 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
490 magnifiedRegionBounds);
491 Rect touchableRegionBounds = mTempRect1;
492 windowState.getTouchableRegion(mTempRegion1);
493 mTempRegion1.getBounds(touchableRegionBounds);
494 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
495 mCallbacks.onRectangleOnScreenRequested(
496 touchableRegionBounds.left,
497 touchableRegionBounds.top,
498 touchableRegionBounds.right,
499 touchableRegionBounds.bottom);
500 }
501 } break;
502 } break;
503 }
504 }
505 }
506
507 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
508 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
509 if (spec != null && !spec.isNop()) {
Robert Carrb1579c82017-09-05 14:54:47 -0700510 if (!windowState.shouldMagnify()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800511 return null;
512 }
513 }
514 return spec;
515 }
516
Phil Weaver70439242016-03-10 15:15:49 -0800517 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Phil Weaver53b690b2017-08-14 17:42:39 -0700518 // Make sure we're working with the most current bounds
519 mMagnifedViewport.recomputeBoundsLocked();
Phil Weaver70439242016-03-10 15:15:49 -0800520 mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400521 }
522
Svetoslav8e3feb12014-02-24 13:46:47 -0800523 public void destroyLocked() {
524 mMagnifedViewport.destroyWindow();
525 }
526
Phil Weaver251db072017-03-28 08:35:38 -0700527 // Can be called outside of a surface transaction
528 public void showMagnificationBoundsIfNeeded() {
529 mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
530 .sendToTarget();
531 }
532
Svetoslav8e3feb12014-02-24 13:46:47 -0800533 /** NOTE: This has to be called within a surface transaction. */
534 public void drawMagnifiedRegionBorderIfNeededLocked() {
535 mMagnifedViewport.drawWindowIfNeededLocked();
536 }
537
538 private final class MagnifiedViewport {
539
Svetoslav8e3feb12014-02-24 13:46:47 -0800540 private final SparseArray<WindowState> mTempWindowStates =
541 new SparseArray<WindowState>();
542
543 private final RectF mTempRectF = new RectF();
544
545 private final Point mTempPoint = new Point();
546
547 private final Matrix mTempMatrix = new Matrix();
548
Phil Weaver70439242016-03-10 15:15:49 -0800549 private final Region mMagnificationRegion = new Region();
550 private final Region mOldMagnificationRegion = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800551
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800552 private final Path mCircularPath;
553
Svetoslav8e3feb12014-02-24 13:46:47 -0800554 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
555
556 private final WindowManager mWindowManager;
557
Svetoslav7505e332014-08-22 12:14:28 -0700558 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800559 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700560 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800561
562 private final ViewportWindow mWindow;
563
564 private boolean mFullRedrawNeeded;
Robert Carrb1579c82017-09-05 14:54:47 -0700565 private int mTempLayer = 0;
Svetoslav8e3feb12014-02-24 13:46:47 -0800566
567 public MagnifiedViewport() {
568 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800569 mBorderWidth = mContext.getResources().getDimension(
570 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700571 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
572 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800573 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800574
Adam Powell01f280d2015-05-18 16:07:42 -0700575 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800576 mCircularPath = new Path();
Rhed Jao02655dc2018-10-30 20:44:52 +0800577 mDisplay.getRealSize(mTempPoint);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800578 final int centerXY = mTempPoint.x / 2;
579 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
580 } else {
581 mCircularPath = null;
582 }
583
Svetoslav8e3feb12014-02-24 13:46:47 -0800584 recomputeBoundsLocked();
585 }
586
Phil Weaver70439242016-03-10 15:15:49 -0800587 public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
588 outMagnificationRegion.set(mMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400589 }
590
Svetoslav8e3feb12014-02-24 13:46:47 -0800591 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
592 if (spec != null) {
593 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
594 } else {
595 mMagnificationSpec.clear();
596 }
597 // If this message is pending we are in a rotation animation and do not want
598 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700599 if (!mHandler.hasMessages(
600 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800601 setMagnifiedRegionBorderShownLocked(
602 isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
Svetoslav8e3feb12014-02-24 13:46:47 -0800603 }
604 }
605
606 public void recomputeBoundsLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800607 mDisplay.getRealSize(mTempPoint);
Svetoslav8e3feb12014-02-24 13:46:47 -0800608 final int screenWidth = mTempPoint.x;
609 final int screenHeight = mTempPoint.y;
610
Phil Weaver70439242016-03-10 15:15:49 -0800611 mMagnificationRegion.set(0, 0, 0, 0);
612 final Region availableBounds = mTempRegion1;
613 availableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800614
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800615 if (mCircularPath != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800616 availableBounds.setPath(mCircularPath, availableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800617 }
618
Svetoslav8e3feb12014-02-24 13:46:47 -0800619 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700620 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800621
622 SparseArray<WindowState> visibleWindows = mTempWindowStates;
623 visibleWindows.clear();
624 populateWindowsOnScreenLocked(visibleWindows);
625
626 final int visibleWindowCount = visibleWindows.size();
627 for (int i = visibleWindowCount - 1; i >= 0; i--) {
628 WindowState windowState = visibleWindows.valueAt(i);
Phil Weaverd321075e2017-06-13 09:13:35 -0700629 if ((windowState.mAttrs.type == TYPE_MAGNIFICATION_OVERLAY)
630 || ((windowState.mAttrs.privateFlags
Robert Carr132c9f52017-07-31 17:02:30 -0700631 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800632 continue;
633 }
634
Phil Weaver65c06702016-03-15 15:33:46 -0700635 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800636 Matrix matrix = mTempMatrix;
637 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700638 Region touchableRegion = mTempRegion3;
639 windowState.getTouchableRegion(touchableRegion);
640 Rect touchableFrame = mTempRect1;
641 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800642 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700643 windowFrame.set(touchableFrame);
chaviw492139a2018-07-16 16:07:35 -0700644 windowFrame.offset(-windowState.getFrameLw().left,
645 -windowState.getFrameLw().top);
Phil Weaver65c06702016-03-15 15:33:46 -0700646 matrix.mapRect(windowFrame);
647 Region windowBounds = mTempRegion2;
648 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
649 (int) windowFrame.right, (int) windowFrame.bottom);
650 // Only update new regions
651 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
Phil Weaver70439242016-03-10 15:15:49 -0800652 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
Phil Weaver65c06702016-03-15 15:33:46 -0700653 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
654 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800655
Robert Carrb1579c82017-09-05 14:54:47 -0700656 if (windowState.shouldMagnify()) {
Phil Weaver70439242016-03-10 15:15:49 -0800657 mMagnificationRegion.op(windowBounds, Region.Op.UNION);
658 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800659 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800660 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Phil Weaver70439242016-03-10 15:15:49 -0800661 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800662 }
663
Jackal Guoc2e12c42019-02-27 17:06:33 +0800664 // Count letterbox into nonMagnifiedBounds
665 if (windowState.isLetterboxedForDisplayCutoutLw()) {
666 Region letterboxBounds = getLetterboxBounds(windowState);
667 nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
668 availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
669 }
670
Phil Weaver65c06702016-03-15 15:33:46 -0700671 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800672 Region accountedBounds = mTempRegion2;
Phil Weaver70439242016-03-10 15:15:49 -0800673 accountedBounds.set(mMagnificationRegion);
Svetoslav8e3feb12014-02-24 13:46:47 -0800674 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
675 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
676
677 if (accountedBounds.isRect()) {
678 Rect accountedFrame = mTempRect1;
679 accountedBounds.getBounds(accountedFrame);
680 if (accountedFrame.width() == screenWidth
681 && accountedFrame.height() == screenHeight) {
682 break;
683 }
684 }
685 }
686
687 visibleWindows.clear();
688
Phil Weaver70439242016-03-10 15:15:49 -0800689 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700690 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800691 Region.Op.INTERSECT);
692
Phil Weaver70439242016-03-10 15:15:49 -0800693 final boolean magnifiedChanged =
694 !mOldMagnificationRegion.equals(mMagnificationRegion);
695 if (magnifiedChanged) {
696 mWindow.setBounds(mMagnificationRegion);
697 final Rect dirtyRect = mTempRect1;
698 if (mFullRedrawNeeded) {
699 mFullRedrawNeeded = false;
700 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
701 screenWidth - mDrawBorderInset,
702 screenHeight - mDrawBorderInset);
703 mWindow.invalidate(dirtyRect);
704 } else {
705 final Region dirtyRegion = mTempRegion3;
706 dirtyRegion.set(mMagnificationRegion);
707 dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
708 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
709 dirtyRegion.getBounds(dirtyRect);
710 mWindow.invalidate(dirtyRect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800711 }
712
Phil Weaver70439242016-03-10 15:15:49 -0800713 mOldMagnificationRegion.set(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500714 final SomeArgs args = SomeArgs.obtain();
Phil Weaver70439242016-03-10 15:15:49 -0800715 args.arg1 = Region.obtain(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500716 mHandler.obtainMessage(
Phil Weaver70439242016-03-10 15:15:49 -0800717 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
718 .sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800719 }
720 }
721
Jackal Guoc2e12c42019-02-27 17:06:33 +0800722 private Region getLetterboxBounds(WindowState windowState) {
723 final AppWindowToken appToken = windowState.mAppToken;
724 if (appToken == null) {
725 return new Region();
726 }
727
728 mDisplay.getRealSize(mTempPoint);
729 final Rect letterboxInsets = appToken.getLetterboxInsets();
730 final int screenWidth = mTempPoint.x;
731 final int screenHeight = mTempPoint.y;
732 final Rect nonLetterboxRect = mTempRect1;
733 final Region letterboxBounds = mTempRegion3;
734 nonLetterboxRect.set(0, 0, screenWidth, screenHeight);
735 nonLetterboxRect.inset(letterboxInsets);
736 letterboxBounds.set(0, 0, screenWidth, screenHeight);
737 letterboxBounds.op(nonLetterboxRect, Region.Op.DIFFERENCE);
738 return letterboxBounds;
739 }
740
Svetoslav8e3feb12014-02-24 13:46:47 -0800741 public void onRotationChangedLocked() {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800742 // If we are showing the magnification border, hide it immediately so
Svetoslav8e3feb12014-02-24 13:46:47 -0800743 // the user does not see strange artifacts during rotation. The screenshot
Casey Burkhardt74922c62017-02-13 12:43:16 -0800744 // used for rotation already has the border. After the rotation is complete
Svetoslav8e3feb12014-02-24 13:46:47 -0800745 // we will show the border.
Casey Burkhardt74922c62017-02-13 12:43:16 -0800746 if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800747 setMagnifiedRegionBorderShownLocked(false, false);
748 final long delay = (long) (mLongAnimationDuration
Robert Carre625fcf2017-09-01 12:36:28 -0700749 * mService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800750 Message message = mHandler.obtainMessage(
751 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
752 mHandler.sendMessageDelayed(message, delay);
753 }
754 recomputeBoundsLocked();
755 mWindow.updateSize();
756 }
757
758 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
759 if (shown) {
760 mFullRedrawNeeded = true;
Phil Weaver70439242016-03-10 15:15:49 -0800761 mOldMagnificationRegion.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800762 }
763 mWindow.setShown(shown, animate);
764 }
765
766 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
767 MagnificationSpec spec = mMagnificationSpec;
Phil Weaver70439242016-03-10 15:15:49 -0800768 mMagnificationRegion.getBounds(rect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800769 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
770 rect.scale(1.0f / spec.scale);
771 }
772
773 public boolean isMagnifyingLocked() {
774 return mMagnificationSpec.scale > 1.0f;
775 }
776
777 public MagnificationSpec getMagnificationSpecLocked() {
778 return mMagnificationSpec;
779 }
780
781 /** NOTE: This has to be called within a surface transaction. */
782 public void drawWindowIfNeededLocked() {
783 recomputeBoundsLocked();
784 mWindow.drawIfNeeded();
785 }
786
787 public void destroyWindow() {
788 mWindow.releaseSurface();
789 }
790
791 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Robert Carrb1579c82017-09-05 14:54:47 -0700792 mTempLayer = 0;
Rhed Jao02655dc2018-10-30 20:44:52 +0800793 mDisplayContent.forAllWindows((w) -> {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800794 if (w.isOnScreen() && w.isVisibleLw()
Phil Weaverd6ce7372018-05-18 09:48:01 -0700795 && (w.mAttrs.alpha != 0)
Wale Ogunwaled1880962016-11-08 10:31:59 -0800796 && !w.mWinAnimator.mEnterAnimationPending) {
Robert Carrb1579c82017-09-05 14:54:47 -0700797 mTempLayer++;
798 outWindows.put(mTempLayer, w);
Svetoslav8e3feb12014-02-24 13:46:47 -0800799 }
Wale Ogunwaled1880962016-11-08 10:31:59 -0800800 }, false /* traverseTopToBottom */ );
Svetoslav8e3feb12014-02-24 13:46:47 -0800801 }
802
803 private final class ViewportWindow {
804 private static final String SURFACE_TITLE = "Magnification Overlay";
805
Svetoslav8e3feb12014-02-24 13:46:47 -0800806 private final Region mBounds = new Region();
807 private final Rect mDirtyRect = new Rect();
808 private final Paint mPaint = new Paint();
809
Svetoslav8e3feb12014-02-24 13:46:47 -0800810 private final SurfaceControl mSurfaceControl;
811 private final Surface mSurface = new Surface();
812
Svet Ganovb21df802014-09-01 19:06:33 -0700813 private final AnimationController mAnimationController;
814
Svetoslav8e3feb12014-02-24 13:46:47 -0800815 private boolean mShown;
816 private int mAlpha;
817
818 private boolean mInvalidated;
819
820 public ViewportWindow(Context context) {
821 SurfaceControl surfaceControl = null;
822 try {
Rhed Jao02655dc2018-10-30 20:44:52 +0800823 mDisplay.getRealSize(mTempPoint);
824 surfaceControl = mDisplayContent
825 .makeOverlay()
Robert Carre625fcf2017-09-01 12:36:28 -0700826 .setName(SURFACE_TITLE)
Vishnu Naire86bd982018-11-28 13:23:17 -0800827 .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo
Robert Carre625fcf2017-09-01 12:36:28 -0700828 .setFormat(PixelFormat.TRANSLUCENT)
829 .build();
Svetoslav8e3feb12014-02-24 13:46:47 -0800830 } catch (OutOfResourcesException oore) {
831 /* ignore */
832 }
833 mSurfaceControl = surfaceControl;
Robert Carre625fcf2017-09-01 12:36:28 -0700834 mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
Phil Weaverd321075e2017-06-13 09:13:35 -0700835 TYPE_MAGNIFICATION_OVERLAY)
Svetoslav8e3feb12014-02-24 13:46:47 -0800836 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
837 mSurfaceControl.setPosition(0, 0);
838 mSurface.copyFrom(mSurfaceControl);
839
Svet Ganovb21df802014-09-01 19:06:33 -0700840 mAnimationController = new AnimationController(context,
Robert Carre625fcf2017-09-01 12:36:28 -0700841 mService.mH.getLooper());
Svet Ganovb21df802014-09-01 19:06:33 -0700842
Svetoslav8e3feb12014-02-24 13:46:47 -0800843 TypedValue typedValue = new TypedValue();
844 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
845 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700846 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800847
848 mPaint.setStyle(Paint.Style.STROKE);
849 mPaint.setStrokeWidth(mBorderWidth);
850 mPaint.setColor(borderColor);
851
Svetoslav8e3feb12014-02-24 13:46:47 -0800852 mInvalidated = true;
853 }
854
855 public void setShown(boolean shown, boolean animate) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700856 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800857 if (mShown == shown) {
858 return;
859 }
860 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700861 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800862 if (DEBUG_VIEWPORT_WINDOW) {
863 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
864 }
865 }
866 }
867
868 @SuppressWarnings("unused")
869 // Called reflectively from an animator.
870 public int getAlpha() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700871 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800872 return mAlpha;
873 }
874 }
875
876 public void setAlpha(int alpha) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700877 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800878 if (mAlpha == alpha) {
879 return;
880 }
881 mAlpha = alpha;
882 invalidate(null);
883 if (DEBUG_VIEWPORT_WINDOW) {
884 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
885 }
886 }
887 }
888
889 public void setBounds(Region bounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700890 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800891 if (mBounds.equals(bounds)) {
892 return;
893 }
894 mBounds.set(bounds);
895 invalidate(mDirtyRect);
896 if (DEBUG_VIEWPORT_WINDOW) {
897 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
898 }
899 }
900 }
901
902 public void updateSize() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700903 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800904 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
Vishnu Naire86bd982018-11-28 13:23:17 -0800905 mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y);
Svetoslav8e3feb12014-02-24 13:46:47 -0800906 invalidate(mDirtyRect);
907 }
908 }
909
910 public void invalidate(Rect dirtyRect) {
911 if (dirtyRect != null) {
912 mDirtyRect.set(dirtyRect);
913 } else {
914 mDirtyRect.setEmpty();
915 }
916 mInvalidated = true;
Robert Carre625fcf2017-09-01 12:36:28 -0700917 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800918 }
919
920 /** NOTE: This has to be called within a surface transaction. */
921 public void drawIfNeeded() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700922 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800923 if (!mInvalidated) {
924 return;
925 }
926 mInvalidated = false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800927 if (mAlpha > 0) {
Adrian Roos69364f52018-04-19 18:49:39 +0200928 Canvas canvas = null;
929 try {
930 // Empty dirty rectangle means unspecified.
931 if (mDirtyRect.isEmpty()) {
932 mBounds.getBounds(mDirtyRect);
933 }
934 mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
935 canvas = mSurface.lockCanvas(mDirtyRect);
936 if (DEBUG_VIEWPORT_WINDOW) {
937 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
938 }
939 } catch (IllegalArgumentException iae) {
940 /* ignore */
941 } catch (Surface.OutOfResourcesException oore) {
942 /* ignore */
943 }
944 if (canvas == null) {
945 return;
946 }
947 if (DEBUG_VIEWPORT_WINDOW) {
948 Slog.i(LOG_TAG, "Bounds: " + mBounds);
949 }
950 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
951 mPaint.setAlpha(mAlpha);
952 Path path = mBounds.getBoundaryPath();
953 canvas.drawPath(path, mPaint);
954
955 mSurface.unlockCanvasAndPost(canvas);
Svetoslav8e3feb12014-02-24 13:46:47 -0800956 mSurfaceControl.show();
957 } else {
958 mSurfaceControl.hide();
959 }
960 }
961 }
962
963 public void releaseSurface() {
chaviw9f6171e2019-06-07 16:33:50 -0700964 mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
Svetoslav8e3feb12014-02-24 13:46:47 -0800965 mSurface.release();
966 }
Svet Ganovb21df802014-09-01 19:06:33 -0700967
968 private final class AnimationController extends Handler {
969 private static final String PROPERTY_NAME_ALPHA = "alpha";
970
971 private static final int MIN_ALPHA = 0;
972 private static final int MAX_ALPHA = 255;
973
974 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
975
976 private final ValueAnimator mShowHideFrameAnimator;
977
978 public AnimationController(Context context, Looper looper) {
979 super(looper);
980 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
981 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
982
983 Interpolator interpolator = new DecelerateInterpolator(2.5f);
984 final long longAnimationDuration = context.getResources().getInteger(
985 com.android.internal.R.integer.config_longAnimTime);
986
987 mShowHideFrameAnimator.setInterpolator(interpolator);
988 mShowHideFrameAnimator.setDuration(longAnimationDuration);
989 }
990
991 public void onFrameShownStateChanged(boolean shown, boolean animate) {
992 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
993 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
994 }
995
996 @Override
997 public void handleMessage(Message message) {
998 switch (message.what) {
999 case MSG_FRAME_SHOWN_STATE_CHANGED: {
1000 final boolean shown = message.arg1 == 1;
1001 final boolean animate = message.arg2 == 1;
1002
1003 if (animate) {
1004 if (mShowHideFrameAnimator.isRunning()) {
1005 mShowHideFrameAnimator.reverse();
1006 } else {
1007 if (shown) {
1008 mShowHideFrameAnimator.start();
1009 } else {
1010 mShowHideFrameAnimator.reverse();
1011 }
1012 }
1013 } else {
1014 mShowHideFrameAnimator.cancel();
1015 if (shown) {
1016 setAlpha(MAX_ALPHA);
1017 } else {
1018 setAlpha(MIN_ALPHA);
1019 }
1020 }
1021 } break;
1022 }
1023 }
1024 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001025 }
1026 }
1027
1028 private class MyHandler extends Handler {
Phil Weaver70439242016-03-10 15:15:49 -08001029 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001030 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
1031 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
1032 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
1033 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
1034
1035 public MyHandler(Looper looper) {
1036 super(looper);
1037 }
1038
1039 @Override
1040 public void handleMessage(Message message) {
1041 switch (message.what) {
Phil Weaver70439242016-03-10 15:15:49 -08001042 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -05001043 final SomeArgs args = (SomeArgs) message.obj;
1044 final Region magnifiedBounds = (Region) args.arg1;
Phil Weaver70439242016-03-10 15:15:49 -08001045 mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -05001046 magnifiedBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -08001047 } break;
1048
1049 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
1050 SomeArgs args = (SomeArgs) message.obj;
1051 final int left = args.argi1;
1052 final int top = args.argi2;
1053 final int right = args.argi3;
1054 final int bottom = args.argi4;
1055 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
1056 args.recycle();
1057 } break;
1058
1059 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
1060 mCallbacks.onUserContextChanged();
1061 } break;
1062
1063 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
1064 final int rotation = message.arg1;
1065 mCallbacks.onRotationChanged(rotation);
1066 } break;
1067
1068 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001069 synchronized (mService.mGlobalLock) {
Casey Burkhardt74922c62017-02-13 12:43:16 -08001070 if (mMagnifedViewport.isMagnifyingLocked()
1071 || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001072 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
Robert Carre625fcf2017-09-01 12:36:28 -07001073 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -08001074 }
1075 }
1076 } break;
1077 }
1078 }
1079 }
1080 }
1081
1082 /**
1083 * This class encapsulates the functionality related to computing the windows
1084 * reported for accessibility purposes. These windows are all windows a sighted
1085 * user can see on the screen.
1086 */
1087 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -08001088 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
1089 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -08001090
1091 private static final boolean DEBUG = false;
1092
Jackal Guo28dce102019-05-28 14:25:17 +08001093 private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001094
Jackal Guo28dce102019-05-28 14:25:17 +08001095 private final Set<IBinder> mTempBinderSet = new ArraySet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001096
1097 private final RectF mTempRectF = new RectF();
1098
1099 private final Matrix mTempMatrix = new Matrix();
1100
1101 private final Point mTempPoint = new Point();
1102
1103 private final Rect mTempRect = new Rect();
1104
1105 private final Region mTempRegion = new Region();
1106
1107 private final Region mTempRegion1 = new Region();
1108
1109 private final Context mContext;
1110
Robert Carre625fcf2017-09-01 12:36:28 -07001111 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001112
1113 private final Handler mHandler;
1114
1115 private final WindowsForAccessibilityCallback mCallback;
1116
Jacky Kaof93252b2019-07-18 15:19:52 +08001117 private final int mDisplayId;
1118
Svetoslavf7174e82014-06-12 11:29:35 -07001119 private final long mRecurringAccessibilityEventsIntervalMillis;
1120
Svetoslav8e3feb12014-02-24 13:46:47 -08001121 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
Jacky Kaof93252b2019-07-18 15:19:52 +08001122 int displayId,
Svetoslav8e3feb12014-02-24 13:46:47 -08001123 WindowsForAccessibilityCallback callback) {
1124 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -07001125 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001126 mCallback = callback;
Jacky Kaof93252b2019-07-18 15:19:52 +08001127 mDisplayId = displayId;
Robert Carre625fcf2017-09-01 12:36:28 -07001128 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -07001129 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1130 .getSendRecurringAccessibilityEventsInterval();
Phil Weaverc72faad2018-07-24 10:53:01 -07001131 computeChangedWindows(true);
Svetoslav8e3feb12014-02-24 13:46:47 -08001132 }
1133
Phil Weaverc72faad2018-07-24 10:53:01 -07001134 public void performComputeChangedWindowsNotLocked(boolean forceSend) {
Svetoslav3a0d8782014-12-04 12:50:11 -08001135 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
Phil Weaverc72faad2018-07-24 10:53:01 -07001136 computeChangedWindows(forceSend);
Svetoslav3a0d8782014-12-04 12:50:11 -08001137 }
1138
Svetoslavf7174e82014-06-12 11:29:35 -07001139 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -08001140 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001141 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1142 mRecurringAccessibilityEventsIntervalMillis);
1143 }
1144 }
1145
Phil Weaverc72faad2018-07-24 10:53:01 -07001146 /**
Jackal Guoc43a0a62019-04-23 09:15:14 +08001147 * Check if windows have changed, and send them to the accessibility subsystem if they have.
Phil Weaverc72faad2018-07-24 10:53:01 -07001148 *
1149 * @param forceSend Send the windows the accessibility even if they haven't changed.
1150 */
1151 public void computeChangedWindows(boolean forceSend) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001152 if (DEBUG) {
1153 Slog.i(LOG_TAG, "computeChangedWindows()");
1154 }
1155
Jackal Guo28dce102019-05-28 14:25:17 +08001156 List<WindowInfo> windows = new ArrayList<>();
Jacky Kao81167402019-08-22 12:05:34 +08001157 final int topFocusedDisplayId;
1158 IBinder topFocusedWindowToken = null;
Svetoslav3a0d8782014-12-04 12:50:11 -08001159
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001160 synchronized (mService.mGlobalLock) {
Jacky Kao81167402019-08-22 12:05:34 +08001161 // Do not send the windows if there is no top focus as
Svetoslavf7174e82014-06-12 11:29:35 -07001162 // the window manager is still looking for where to put it.
1163 // We will do the work when we get a focus change callback.
Jacky Kao81167402019-08-22 12:05:34 +08001164 final WindowState topFocusedWindowState = getTopFocusWindow();
1165 if (topFocusedWindowState == null) return;
Svetoslavf7174e82014-06-12 11:29:35 -07001166
Jacky Kaof93252b2019-07-18 15:19:52 +08001167 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
1168 if (dc == null) {
1169 return;
1170 }
1171 final Display display = dc.getDisplay();
1172 display.getRealSize(mTempPoint);
Svetoslav8e3feb12014-02-24 13:46:47 -08001173 final int screenWidth = mTempPoint.x;
1174 final int screenHeight = mTempPoint.y;
1175
1176 Region unaccountedSpace = mTempRegion;
1177 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1178
Wale Ogunwalef7cab102016-10-25 15:25:14 -07001179 final SparseArray<WindowState> visibleWindows = mTempWindowStates;
Svetoslav8e3feb12014-02-24 13:46:47 -08001180 populateVisibleWindowsOnScreenLocked(visibleWindows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001181 Set<IBinder> addedWindows = mTempBinderSet;
1182 addedWindows.clear();
1183
Svetoslavf7174e82014-06-12 11:29:35 -07001184 boolean focusedWindowAdded = false;
1185
Svetoslav8e3feb12014-02-24 13:46:47 -08001186 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001187 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001188
1189 // Iterate until we figure out what is touchable for the entire screen.
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001190 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001191 final WindowState windowState = visibleWindows.valueAt(i);
Jackal Guof3823712019-05-20 10:16:06 +08001192 final Region regionInScreen = new Region();
1193 computeWindowRegionInScreen(windowState, regionInScreen);
Allen Hairf20ac2c2016-02-11 17:42:59 -08001194
Jackal Guof3823712019-05-20 10:16:06 +08001195 if (windowMattersToAccessibility(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001196 skipRemainingWindowsForTasks)) {
Jackal Guof3823712019-05-20 10:16:06 +08001197 addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows);
1198 updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001199 skipRemainingWindowsForTasks);
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001200 focusedWindowAdded |= windowState.isFocused();
1201 }
1202
1203 if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
1204 break;
Svetoslavf7174e82014-06-12 11:29:35 -07001205 }
1206 }
1207
Svetoslav8e3feb12014-02-24 13:46:47 -08001208 // Remove child/parent references to windows that were not added.
1209 final int windowCount = windows.size();
1210 for (int i = 0; i < windowCount; i++) {
1211 WindowInfo window = windows.get(i);
1212 if (!addedWindows.contains(window.parentToken)) {
1213 window.parentToken = null;
1214 }
1215 if (window.childTokens != null) {
1216 final int childTokenCount = window.childTokens.size();
1217 for (int j = childTokenCount - 1; j >= 0; j--) {
1218 if (!addedWindows.contains(window.childTokens.get(j))) {
1219 window.childTokens.remove(j);
1220 }
1221 }
1222 // Leave the child token list if empty.
1223 }
1224 }
1225
1226 visibleWindows.clear();
1227 addedWindows.clear();
Svetoslav3a0d8782014-12-04 12:50:11 -08001228
Jacky Kao81167402019-08-22 12:05:34 +08001229 // Gets the top focused display Id and window token for supporting multi-display.
1230 topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
1231 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
1232 }
1233 mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
1234 topFocusedWindowToken, windows);
Svetoslav3a0d8782014-12-04 12:50:11 -08001235
1236 // Recycle the windows as we do not need them.
1237 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001238 }
1239
Jackal Guof3823712019-05-20 10:16:06 +08001240 private boolean windowMattersToAccessibility(WindowState windowState,
1241 Region regionInScreen, Region unaccountedSpace,
1242 HashSet<Integer> skipRemainingWindowsForTasks) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001243 if (windowState.isFocused()) {
1244 return true;
1245 }
1246
1247 // If the window is part of a task that we're finished with - ignore.
1248 final Task task = windowState.getTask();
1249 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1250 return false;
1251 }
1252
1253 // Ignore non-touchable windows, except the split-screen divider, which is
1254 // occasionally non-touchable but still useful for identifying split-screen
1255 // mode.
1256 if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
1257 && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
1258 return false;
1259 }
1260
1261 // If the window is completely covered by other windows - ignore.
Jackal Guof3823712019-05-20 10:16:06 +08001262 if (unaccountedSpace.quickReject(regionInScreen)) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001263 return false;
1264 }
1265
1266 // Add windows of certain types not covered by modal windows.
1267 if (isReportedWindowType(windowState.mAttrs.type)) {
1268 return true;
1269 }
1270
1271 return false;
1272 }
1273
Jackal Guof3823712019-05-20 10:16:06 +08001274 private void updateUnaccountedSpace(WindowState windowState, Region regionInScreen,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001275 Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
1276 if (windowState.mAttrs.type
1277 != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1278
1279 // Account for the space this window takes if the window
1280 // is not an accessibility overlay which does not change
1281 // the reported windows.
Jackal Guof3823712019-05-20 10:16:06 +08001282 unaccountedSpace.op(regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001283 Region.Op.REVERSE_DIFFERENCE);
1284
1285 // If a window is modal it prevents other windows from being touched
1286 if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1287 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Jackal Guof3823712019-05-20 10:16:06 +08001288 if (!windowState.hasTapExcludeRegion()) {
1289 // Account for all space in the task, whether the windows in it are
1290 // touchable or not. The modal window blocks all touches from the task's
1291 // area.
1292 unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
1293 Region.Op.REVERSE_DIFFERENCE);
1294 } else {
1295 // If a window has tap exclude region, we need to account it.
1296 final Region displayRegion = new Region(windowState.getDisplayFrameLw());
1297 final Region tapExcludeRegion = new Region();
1298 windowState.amendTapExcludeRegion(tapExcludeRegion);
1299 displayRegion.op(tapExcludeRegion, displayRegion,
1300 Region.Op.REVERSE_DIFFERENCE);
1301 unaccountedSpace.op(displayRegion, unaccountedSpace,
1302 Region.Op.REVERSE_DIFFERENCE);
1303 }
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001304
1305 final Task task = windowState.getTask();
1306 if (task != null) {
1307 // If the window is associated with a particular task, we can skip the
1308 // rest of the windows for that task.
1309 skipRemainingWindowsForTasks.add(task.mTaskId);
Jackal Guof3823712019-05-20 10:16:06 +08001310 } else if (!windowState.hasTapExcludeRegion()) {
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001311 // If the window is not associated with a particular task, then it is
Jackal Guof3823712019-05-20 10:16:06 +08001312 // globally modal. In this case we can skip all remaining windows when
1313 // it doesn't has tap exclude region.
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001314 unaccountedSpace.setEmpty();
1315 }
1316 }
1317 }
1318 }
1319
Jackal Guof3823712019-05-20 10:16:06 +08001320 private void computeWindowRegionInScreen(WindowState windowState, Region outRegion) {
Svetoslavf7174e82014-06-12 11:29:35 -07001321 // Get the touchable frame.
1322 Region touchableRegion = mTempRegion1;
1323 windowState.getTouchableRegion(touchableRegion);
Svetoslavf7174e82014-06-12 11:29:35 -07001324
1325 // Map the frame to get what appears on the screen.
1326 Matrix matrix = mTempMatrix;
1327 populateTransformationMatrixLocked(windowState, matrix);
Svetoslavf7174e82014-06-12 11:29:35 -07001328
Jackal Guof3823712019-05-20 10:16:06 +08001329 forEachRect(touchableRegion, rect -> {
1330 // Move to origin as all transforms are captured by the matrix.
1331 RectF windowFrame = mTempRectF;
1332 windowFrame.set(rect);
1333 windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
1334
1335 matrix.mapRect(windowFrame);
1336
1337 // Union all rects.
1338 outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
1339 (int) windowFrame.right, (int) windowFrame.bottom));
1340 });
Svetoslavf7174e82014-06-12 11:29:35 -07001341 }
1342
Jackal Guof3823712019-05-20 10:16:06 +08001343 private static void addPopulatedWindowInfo(WindowState windowState, Region regionInScreen,
Eugene Susla18e7fc112018-03-16 14:35:31 -07001344 List<WindowInfo> out, Set<IBinder> tokenOut) {
Wale Ogunwaleadde52e2016-07-16 13:11:55 -07001345 final WindowInfo window = windowState.getWindowInfo();
Jackal Guof3823712019-05-20 10:16:06 +08001346 window.regionInScreen.set(regionInScreen);
Eugene Susla18e7fc112018-03-16 14:35:31 -07001347 window.layer = tokenOut.size();
1348 out.add(window);
1349 tokenOut.add(window.token);
Svetoslavf7174e82014-06-12 11:29:35 -07001350 }
1351
Svetoslav3a0d8782014-12-04 12:50:11 -08001352 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001353 final int windowCount = windows.size();
1354 for (int i = windowCount - 1; i >= 0; i--) {
1355 windows.remove(i).recycle();
1356 }
1357 }
1358
1359 private static boolean isReportedWindowType(int windowType) {
Jorim Jaggi73294b62016-10-26 18:02:36 -07001360 return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
Svetoslav8e3feb12014-02-24 13:46:47 -08001361 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1362 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1363 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001364 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001365 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Phil Weaverd321075e2017-06-13 09:13:35 -07001366 && windowType != TYPE_MAGNIFICATION_OVERLAY
Svetoslav8e3feb12014-02-24 13:46:47 -08001367 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1368 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1369 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1370 }
1371
1372 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001373 final List<WindowState> tempWindowStatesList = new ArrayList<>();
Jacky Kaof93252b2019-07-18 15:19:52 +08001374 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
1375 if (dc == null) {
1376 return;
1377 }
1378
Jackal Guof3823712019-05-20 10:16:06 +08001379 dc.forAllWindows(w -> {
Wale Ogunwaled1880962016-11-08 10:31:59 -08001380 if (w.isVisibleLw()) {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001381 tempWindowStatesList.add(w);
Svetoslav8e3feb12014-02-24 13:46:47 -08001382 }
Tiger Huangd8ec9382019-04-18 14:35:09 -07001383 }, false /* traverseTopToBottom */);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001384 // Insert the re-parented windows in another display on top of their parents in
1385 // default display.
Tiger Huangd8ec9382019-04-18 14:35:09 -07001386 mService.mRoot.forAllWindows(w -> {
Jackal Guoc43a0a62019-04-23 09:15:14 +08001387 final WindowState parentWindow = findRootDisplayParentWindow(w);
1388 if (parentWindow == null) {
1389 return;
Tiger Huangd8ec9382019-04-18 14:35:09 -07001390 }
Jackal Guoc43a0a62019-04-23 09:15:14 +08001391
Jacky Kaof93252b2019-07-18 15:19:52 +08001392 if (w.isVisibleLw() && tempWindowStatesList.contains(parentWindow)) {
Jackal Guof3823712019-05-20 10:16:06 +08001393 tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001394 }
Jackal Guof3823712019-05-20 10:16:06 +08001395 }, false /* traverseTopToBottom */);
Jackal Guoc43a0a62019-04-23 09:15:14 +08001396 for (int i = 0; i < tempWindowStatesList.size(); i++) {
1397 outWindows.put(i, tempWindowStatesList.get(i));
1398 }
Tiger Huangd8ec9382019-04-18 14:35:09 -07001399 }
1400
1401 private WindowState findRootDisplayParentWindow(WindowState win) {
1402 WindowState displayParentWindow = win.getDisplayContent().getParentWindow();
1403 if (displayParentWindow == null) {
1404 return null;
1405 }
1406 WindowState candidate = displayParentWindow;
1407 while (candidate != null) {
1408 displayParentWindow = candidate;
1409 candidate = displayParentWindow.getDisplayContent().getParentWindow();
1410 }
1411 return displayParentWindow;
Svetoslav8e3feb12014-02-24 13:46:47 -08001412 }
Jackal Guoc43a0a62019-04-23 09:15:14 +08001413
Jacky Kao81167402019-08-22 12:05:34 +08001414 private WindowState getTopFocusWindow() {
1415 return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
Jackal Guoc43a0a62019-04-23 09:15:14 +08001416 }
1417
Svetoslav8e3feb12014-02-24 13:46:47 -08001418 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001419 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001420
1421 public MyHandler(Looper looper) {
1422 super(looper, null, false);
1423 }
1424
1425 @Override
1426 @SuppressWarnings("unchecked")
1427 public void handleMessage(Message message) {
1428 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001429 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
Phil Weaverc72faad2018-07-24 10:53:01 -07001430 computeChangedWindows(false);
Svetoslavf7174e82014-06-12 11:29:35 -07001431 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001432 }
1433 }
1434 }
1435 }
1436}