blob: 26ca975bfc8ffd7eb9aa5a35705f501972d0c2e8 [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
127 final Display display = dc.getDisplay();
128 if (mWindowsForAccessibilityObserver.get(displayId) != null) {
129 if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
130 // The window observer of this embedded display had been set from
131 // window manager after setting its parent window
132 return true;
133 } else {
134 throw new IllegalStateException(
135 "Windows for accessibility callback of display "
136 + displayId + " already set!");
137 }
138 }
139 if (display.getType() == Display.TYPE_OVERLAY) {
140 return false;
141 }
142 mWindowsForAccessibilityObserver.put(displayId,
143 new WindowsForAccessibilityObserver(mService, displayId, callback));
Svetoslav8e3feb12014-02-24 13:46:47 -0800144 } else {
Jacky Kaof93252b2019-07-18 15:19:52 +0800145 final WindowsForAccessibilityObserver windowsForA11yObserver =
146 mWindowsForAccessibilityObserver.get(displayId);
147 if (windowsForA11yObserver == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800148 throw new IllegalStateException(
Jacky Kaof93252b2019-07-18 15:19:52 +0800149 "Windows for accessibility callback of display " + displayId
150 + " already cleared!");
Svetoslav8e3feb12014-02-24 13:46:47 -0800151 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800152 mWindowsForAccessibilityObserver.remove(displayId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800153 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800154 return true;
Svetoslav8e3feb12014-02-24 13:46:47 -0800155 }
156
Jacky Kaof93252b2019-07-18 15:19:52 +0800157 public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) {
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700158 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700159 synchronized (mService) {
Jacky Kaof93252b2019-07-18 15:19:52 +0800160 final WindowsForAccessibilityObserver windowsForA11yObserver =
161 mWindowsForAccessibilityObserver.get(displayId);
162 if (windowsForA11yObserver != null) {
163 observer = windowsForA11yObserver;
164 }
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700165 }
166 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700167 observer.performComputeChangedWindowsNotLocked(forceSend);
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700168 }
169 }
170
Rhed Jao02655dc2018-10-30 20:44:52 +0800171 public void setMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
172 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
173 if (displayMagnifier != null) {
174 displayMagnifier.setMagnificationSpecLocked(spec);
Svetoslav8e3feb12014-02-24 13:46:47 -0800175 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800176 final WindowsForAccessibilityObserver windowsForA11yObserver =
177 mWindowsForAccessibilityObserver.get(displayId);
178 if (windowsForA11yObserver != null) {
179 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800180 }
181 }
182
Rhed Jao02655dc2018-10-30 20:44:52 +0800183 public void getMagnificationRegionLocked(int displayId, Region outMagnificationRegion) {
184 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
185 if (displayMagnifier != null) {
186 displayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400187 }
188 }
189
Rhed Jao02655dc2018-10-30 20:44:52 +0800190 public void onRectangleOnScreenRequestedLocked(int displayId, Rect rectangle) {
191 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
192 if (displayMagnifier != null) {
193 displayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800194 }
195 // Not relevant for the window observer.
196 }
197
Rhed Jao02655dc2018-10-30 20:44:52 +0800198 public void onWindowLayersChangedLocked(int displayId) {
199 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
200 if (displayMagnifier != null) {
201 displayMagnifier.onWindowLayersChangedLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800202 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800203 final WindowsForAccessibilityObserver windowsForA11yObserver =
204 mWindowsForAccessibilityObserver.get(displayId);
205 if (windowsForA11yObserver != null) {
206 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800207 }
208 }
209
Andrii Kulian8ee72852017-03-10 10:36:45 -0800210 public void onRotationChangedLocked(DisplayContent displayContent) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800211 final int displayId = displayContent.getDisplayId();
212 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
213 if (displayMagnifier != null) {
214 displayMagnifier.onRotationChangedLocked(displayContent);
Svetoslav8e3feb12014-02-24 13:46:47 -0800215 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800216 final WindowsForAccessibilityObserver windowsForA11yObserver =
217 mWindowsForAccessibilityObserver.get(displayId);
218 if (windowsForA11yObserver != null) {
219 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800220 }
221 }
222
223 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800224 final int displayId = windowState.getDisplayId();
225 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
226 if (displayMagnifier != null) {
227 displayMagnifier.onAppWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800228 }
229 // Not relevant for the window observer.
230 }
231
232 public void onWindowTransitionLocked(WindowState windowState, int transition) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800233 final int displayId = windowState.getDisplayId();
234 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
235 if (displayMagnifier != null) {
236 displayMagnifier.onWindowTransitionLocked(windowState, transition);
Svetoslav8e3feb12014-02-24 13:46:47 -0800237 }
Jacky Kaof93252b2019-07-18 15:19:52 +0800238 final WindowsForAccessibilityObserver windowsForA11yObserver =
239 mWindowsForAccessibilityObserver.get(displayId);
240 if (windowsForA11yObserver != null) {
241 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800242 }
243 }
244
Jacky Kaof93252b2019-07-18 15:19:52 +0800245 public void onWindowFocusChangedNotLocked(int displayId) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800246 // Not relevant for the display magnifier.
247
Svetoslav3a0d8782014-12-04 12:50:11 -0800248 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700249 synchronized (mService) {
Jacky Kaof93252b2019-07-18 15:19:52 +0800250 final WindowsForAccessibilityObserver windowsForA11yObserver =
251 mWindowsForAccessibilityObserver.get(displayId);
252 if (windowsForA11yObserver != null) {
253 observer = windowsForA11yObserver;
254 }
Svetoslav3a0d8782014-12-04 12:50:11 -0800255 }
256 if (observer != null) {
Phil Weaverc72faad2018-07-24 10:53:01 -0700257 observer.performComputeChangedWindowsNotLocked(false);
Svetoslav8e3feb12014-02-24 13:46:47 -0800258 }
259 }
260
Jacky Kaof93252b2019-07-18 15:19:52 +0800261 public void onSomeWindowResizedOrMovedLocked(int displayId) {
Svetoslav4604abc2014-06-10 18:59:30 -0700262 // Not relevant for the display magnifier.
263
Jacky Kaof93252b2019-07-18 15:19:52 +0800264 final WindowsForAccessibilityObserver windowsForA11yObserver =
265 mWindowsForAccessibilityObserver.get(displayId);
266 if (windowsForA11yObserver != null) {
267 windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700268 }
269 }
270
Svetoslav8e3feb12014-02-24 13:46:47 -0800271 /** NOTE: This has to be called within a surface transaction. */
Rhed Jao02655dc2018-10-30 20:44:52 +0800272 public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) {
273 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
274 if (displayMagnifier != null) {
275 displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800276 }
277 // Not relevant for the window observer.
278 }
279
280 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
Rhed Jao02655dc2018-10-30 20:44:52 +0800281 final int displayId = windowState.getDisplayId();
282 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
283 if (displayMagnifier != null) {
284 return displayMagnifier.getMagnificationSpecForWindowLocked(windowState);
Svetoslav8e3feb12014-02-24 13:46:47 -0800285 }
286 return null;
287 }
288
289 public boolean hasCallbacksLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800290 // TODO: support multi-display for windows observer
291 return (mDisplayMagnifiers.size() > 0
Svetoslav8e3feb12014-02-24 13:46:47 -0800292 || mWindowsForAccessibilityObserver != null);
293 }
294
Rhed Jao02655dc2018-10-30 20:44:52 +0800295 public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) {
296 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
297 if (displayMagnifier != null) {
298 displayMagnifier.setForceShowMagnifiableBoundsLocked(show);
299 displayMagnifier.showMagnificationBoundsIfNeeded();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800300 }
301 }
302
Jacky Kaof93252b2019-07-18 15:19:52 +0800303 public void handleWindowObserverOfEmbeddedDisplayLocked(int embeddedDisplayId,
304 WindowState parentWindow) {
305 if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
306 return;
307 }
308 // Finds the parent display of this embedded display
309 final int parentDisplayId;
310 WindowState candidate = parentWindow;
311 while (candidate != null) {
312 parentWindow = candidate;
313 candidate = parentWindow.getDisplayContent().getParentWindow();
314 }
315 parentDisplayId = parentWindow.getDisplayId();
316 // Uses the observer of parent display
317 final WindowsForAccessibilityObserver windowsForA11yObserver =
318 mWindowsForAccessibilityObserver.get(parentDisplayId);
319
320 if (windowsForA11yObserver != null) {
321 // Replaces the observer of embedded display to the one of parent display
322 mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
323 }
324 }
325
Svetoslav8e3feb12014-02-24 13:46:47 -0800326 private static void populateTransformationMatrixLocked(WindowState windowState,
327 Matrix outMatrix) {
Jorim Jaggieb0d3bc2017-12-15 14:56:19 +0100328 windowState.getTransformationMatrix(sTempFloats, outMatrix);
Svetoslav8e3feb12014-02-24 13:46:47 -0800329 }
330
331 /**
332 * This class encapsulates the functionality related to display magnification.
333 */
334 private static final class DisplayMagnifier {
335
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800336 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800337
338 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
339 private static final boolean DEBUG_ROTATION = false;
340 private static final boolean DEBUG_LAYERS = false;
341 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
342 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
343
344 private final Rect mTempRect1 = new Rect();
345 private final Rect mTempRect2 = new Rect();
346
347 private final Region mTempRegion1 = new Region();
348 private final Region mTempRegion2 = new Region();
349 private final Region mTempRegion3 = new Region();
350 private final Region mTempRegion4 = new Region();
351
352 private final Context mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700353 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800354 private final MagnifiedViewport mMagnifedViewport;
355 private final Handler mHandler;
Rhed Jao02655dc2018-10-30 20:44:52 +0800356 private final DisplayContent mDisplayContent;
357 private final Display mDisplay;
Svetoslav8e3feb12014-02-24 13:46:47 -0800358
359 private final MagnificationCallbacks mCallbacks;
360
361 private final long mLongAnimationDuration;
362
Casey Burkhardt74922c62017-02-13 12:43:16 -0800363 private boolean mForceShowMagnifiableBounds = false;
364
Svetoslav8e3feb12014-02-24 13:46:47 -0800365 public DisplayMagnifier(WindowManagerService windowManagerService,
Rhed Jao02655dc2018-10-30 20:44:52 +0800366 DisplayContent displayContent,
367 Display display,
Svetoslav8e3feb12014-02-24 13:46:47 -0800368 MagnificationCallbacks callbacks) {
369 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700370 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800371 mCallbacks = callbacks;
Rhed Jao02655dc2018-10-30 20:44:52 +0800372 mDisplayContent = displayContent;
373 mDisplay = display;
Robert Carre625fcf2017-09-01 12:36:28 -0700374 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslav8e3feb12014-02-24 13:46:47 -0800375 mMagnifedViewport = new MagnifiedViewport();
376 mLongAnimationDuration = mContext.getResources().getInteger(
377 com.android.internal.R.integer.config_longAnimTime);
378 }
379
380 public void setMagnificationSpecLocked(MagnificationSpec spec) {
381 mMagnifedViewport.updateMagnificationSpecLocked(spec);
382 mMagnifedViewport.recomputeBoundsLocked();
Robert Carrb1579c82017-09-05 14:54:47 -0700383
Rhed Jao02655dc2018-10-30 20:44:52 +0800384 mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
Robert Carre625fcf2017-09-01 12:36:28 -0700385 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800386 }
387
Casey Burkhardt74922c62017-02-13 12:43:16 -0800388 public void setForceShowMagnifiableBoundsLocked(boolean show) {
389 mForceShowMagnifiableBounds = show;
390 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
391 }
392
393 public boolean isForceShowingMagnifiableBoundsLocked() {
394 return mForceShowMagnifiableBounds;
395 }
396
Svetoslavf7174e82014-06-12 11:29:35 -0700397 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800398 if (DEBUG_RECTANGLE_REQUESTED) {
399 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
400 }
401 if (!mMagnifedViewport.isMagnifyingLocked()) {
402 return;
403 }
404 Rect magnifiedRegionBounds = mTempRect2;
405 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
406 if (magnifiedRegionBounds.contains(rectangle)) {
407 return;
408 }
409 SomeArgs args = SomeArgs.obtain();
410 args.argi1 = rectangle.left;
411 args.argi2 = rectangle.top;
412 args.argi3 = rectangle.right;
413 args.argi4 = rectangle.bottom;
414 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
415 args).sendToTarget();
416 }
417
418 public void onWindowLayersChangedLocked() {
419 if (DEBUG_LAYERS) {
420 Slog.i(LOG_TAG, "Layers changed.");
421 }
422 mMagnifedViewport.recomputeBoundsLocked();
Robert Carre625fcf2017-09-01 12:36:28 -0700423 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800424 }
425
Andrii Kulian8ee72852017-03-10 10:36:45 -0800426 public void onRotationChangedLocked(DisplayContent displayContent) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800427 if (DEBUG_ROTATION) {
Andrii Kulian8ee72852017-03-10 10:36:45 -0800428 final int rotation = displayContent.getRotation();
429 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
Svetoslav8e3feb12014-02-24 13:46:47 -0800430 + " displayId: " + displayContent.getDisplayId());
431 }
432 mMagnifedViewport.onRotationChangedLocked();
433 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
434 }
435
436 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
437 if (DEBUG_WINDOW_TRANSITIONS) {
438 Slog.i(LOG_TAG, "Window transition: "
439 + AppTransition.appTransitionToString(transition)
440 + " displayId: " + windowState.getDisplayId());
441 }
442 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
443 if (magnifying) {
444 switch (transition) {
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100445 case WindowManager.TRANSIT_ACTIVITY_OPEN:
446 case WindowManager.TRANSIT_TASK_OPEN:
447 case WindowManager.TRANSIT_TASK_TO_FRONT:
448 case WindowManager.TRANSIT_WALLPAPER_OPEN:
449 case WindowManager.TRANSIT_WALLPAPER_CLOSE:
450 case WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800451 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
452 }
453 }
454 }
455 }
456
457 public void onWindowTransitionLocked(WindowState windowState, int transition) {
458 if (DEBUG_WINDOW_TRANSITIONS) {
459 Slog.i(LOG_TAG, "Window transition: "
460 + AppTransition.appTransitionToString(transition)
461 + " displayId: " + windowState.getDisplayId());
462 }
463 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
464 final int type = windowState.mAttrs.type;
465 switch (transition) {
466 case WindowManagerPolicy.TRANSIT_ENTER:
467 case WindowManagerPolicy.TRANSIT_SHOW: {
468 if (!magnifying) {
469 break;
470 }
471 switch (type) {
472 case WindowManager.LayoutParams.TYPE_APPLICATION:
Chong Zhangfea963e2016-08-15 17:14:16 -0700473 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
Svetoslav8e3feb12014-02-24 13:46:47 -0800474 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
475 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
476 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700477 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800478 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
479 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
480 case WindowManager.LayoutParams.TYPE_PHONE:
481 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
482 case WindowManager.LayoutParams.TYPE_TOAST:
483 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800484 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
Svetoslav8e3feb12014-02-24 13:46:47 -0800485 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
486 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
487 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
488 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
489 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500490 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200491 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800492 Rect magnifiedRegionBounds = mTempRect2;
493 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
494 magnifiedRegionBounds);
495 Rect touchableRegionBounds = mTempRect1;
496 windowState.getTouchableRegion(mTempRegion1);
497 mTempRegion1.getBounds(touchableRegionBounds);
498 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
499 mCallbacks.onRectangleOnScreenRequested(
500 touchableRegionBounds.left,
501 touchableRegionBounds.top,
502 touchableRegionBounds.right,
503 touchableRegionBounds.bottom);
504 }
505 } break;
506 } break;
507 }
508 }
509 }
510
511 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
512 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
513 if (spec != null && !spec.isNop()) {
Robert Carrb1579c82017-09-05 14:54:47 -0700514 if (!windowState.shouldMagnify()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800515 return null;
516 }
517 }
518 return spec;
519 }
520
Phil Weaver70439242016-03-10 15:15:49 -0800521 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Phil Weaver53b690b2017-08-14 17:42:39 -0700522 // Make sure we're working with the most current bounds
523 mMagnifedViewport.recomputeBoundsLocked();
Phil Weaver70439242016-03-10 15:15:49 -0800524 mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400525 }
526
Svetoslav8e3feb12014-02-24 13:46:47 -0800527 public void destroyLocked() {
528 mMagnifedViewport.destroyWindow();
529 }
530
Phil Weaver251db072017-03-28 08:35:38 -0700531 // Can be called outside of a surface transaction
532 public void showMagnificationBoundsIfNeeded() {
533 mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
534 .sendToTarget();
535 }
536
Svetoslav8e3feb12014-02-24 13:46:47 -0800537 /** NOTE: This has to be called within a surface transaction. */
538 public void drawMagnifiedRegionBorderIfNeededLocked() {
539 mMagnifedViewport.drawWindowIfNeededLocked();
540 }
541
542 private final class MagnifiedViewport {
543
Svetoslav8e3feb12014-02-24 13:46:47 -0800544 private final SparseArray<WindowState> mTempWindowStates =
545 new SparseArray<WindowState>();
546
547 private final RectF mTempRectF = new RectF();
548
549 private final Point mTempPoint = new Point();
550
551 private final Matrix mTempMatrix = new Matrix();
552
Phil Weaver70439242016-03-10 15:15:49 -0800553 private final Region mMagnificationRegion = new Region();
554 private final Region mOldMagnificationRegion = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800555
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800556 private final Path mCircularPath;
557
Svetoslav8e3feb12014-02-24 13:46:47 -0800558 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
559
560 private final WindowManager mWindowManager;
561
Svetoslav7505e332014-08-22 12:14:28 -0700562 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800563 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700564 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800565
566 private final ViewportWindow mWindow;
567
568 private boolean mFullRedrawNeeded;
Robert Carrb1579c82017-09-05 14:54:47 -0700569 private int mTempLayer = 0;
Svetoslav8e3feb12014-02-24 13:46:47 -0800570
571 public MagnifiedViewport() {
572 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800573 mBorderWidth = mContext.getResources().getDimension(
574 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700575 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
576 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800577 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800578
Adam Powell01f280d2015-05-18 16:07:42 -0700579 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800580 mCircularPath = new Path();
Rhed Jao02655dc2018-10-30 20:44:52 +0800581 mDisplay.getRealSize(mTempPoint);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800582 final int centerXY = mTempPoint.x / 2;
583 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
584 } else {
585 mCircularPath = null;
586 }
587
Svetoslav8e3feb12014-02-24 13:46:47 -0800588 recomputeBoundsLocked();
589 }
590
Phil Weaver70439242016-03-10 15:15:49 -0800591 public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
592 outMagnificationRegion.set(mMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400593 }
594
Svetoslav8e3feb12014-02-24 13:46:47 -0800595 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
596 if (spec != null) {
597 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
598 } else {
599 mMagnificationSpec.clear();
600 }
601 // If this message is pending we are in a rotation animation and do not want
602 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700603 if (!mHandler.hasMessages(
604 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800605 setMagnifiedRegionBorderShownLocked(
606 isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
Svetoslav8e3feb12014-02-24 13:46:47 -0800607 }
608 }
609
610 public void recomputeBoundsLocked() {
Rhed Jao02655dc2018-10-30 20:44:52 +0800611 mDisplay.getRealSize(mTempPoint);
Svetoslav8e3feb12014-02-24 13:46:47 -0800612 final int screenWidth = mTempPoint.x;
613 final int screenHeight = mTempPoint.y;
614
Phil Weaver70439242016-03-10 15:15:49 -0800615 mMagnificationRegion.set(0, 0, 0, 0);
616 final Region availableBounds = mTempRegion1;
617 availableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800618
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800619 if (mCircularPath != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800620 availableBounds.setPath(mCircularPath, availableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800621 }
622
Svetoslav8e3feb12014-02-24 13:46:47 -0800623 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700624 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800625
626 SparseArray<WindowState> visibleWindows = mTempWindowStates;
627 visibleWindows.clear();
628 populateWindowsOnScreenLocked(visibleWindows);
629
630 final int visibleWindowCount = visibleWindows.size();
631 for (int i = visibleWindowCount - 1; i >= 0; i--) {
632 WindowState windowState = visibleWindows.valueAt(i);
Phil Weaverd321075e2017-06-13 09:13:35 -0700633 if ((windowState.mAttrs.type == TYPE_MAGNIFICATION_OVERLAY)
634 || ((windowState.mAttrs.privateFlags
Robert Carr132c9f52017-07-31 17:02:30 -0700635 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800636 continue;
637 }
638
Phil Weaver65c06702016-03-15 15:33:46 -0700639 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800640 Matrix matrix = mTempMatrix;
641 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700642 Region touchableRegion = mTempRegion3;
643 windowState.getTouchableRegion(touchableRegion);
644 Rect touchableFrame = mTempRect1;
645 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800646 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700647 windowFrame.set(touchableFrame);
chaviw492139a2018-07-16 16:07:35 -0700648 windowFrame.offset(-windowState.getFrameLw().left,
649 -windowState.getFrameLw().top);
Phil Weaver65c06702016-03-15 15:33:46 -0700650 matrix.mapRect(windowFrame);
651 Region windowBounds = mTempRegion2;
652 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
653 (int) windowFrame.right, (int) windowFrame.bottom);
654 // Only update new regions
655 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
Phil Weaver70439242016-03-10 15:15:49 -0800656 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
Phil Weaver65c06702016-03-15 15:33:46 -0700657 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
658 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800659
Robert Carrb1579c82017-09-05 14:54:47 -0700660 if (windowState.shouldMagnify()) {
Phil Weaver70439242016-03-10 15:15:49 -0800661 mMagnificationRegion.op(windowBounds, Region.Op.UNION);
662 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800663 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800664 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Phil Weaver70439242016-03-10 15:15:49 -0800665 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800666 }
667
Jackal Guoc2e12c42019-02-27 17:06:33 +0800668 // Count letterbox into nonMagnifiedBounds
669 if (windowState.isLetterboxedForDisplayCutoutLw()) {
670 Region letterboxBounds = getLetterboxBounds(windowState);
671 nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
672 availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
673 }
674
Phil Weaver65c06702016-03-15 15:33:46 -0700675 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800676 Region accountedBounds = mTempRegion2;
Phil Weaver70439242016-03-10 15:15:49 -0800677 accountedBounds.set(mMagnificationRegion);
Svetoslav8e3feb12014-02-24 13:46:47 -0800678 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
679 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
680
681 if (accountedBounds.isRect()) {
682 Rect accountedFrame = mTempRect1;
683 accountedBounds.getBounds(accountedFrame);
684 if (accountedFrame.width() == screenWidth
685 && accountedFrame.height() == screenHeight) {
686 break;
687 }
688 }
689 }
690
691 visibleWindows.clear();
692
Phil Weaver70439242016-03-10 15:15:49 -0800693 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700694 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800695 Region.Op.INTERSECT);
696
Phil Weaver70439242016-03-10 15:15:49 -0800697 final boolean magnifiedChanged =
698 !mOldMagnificationRegion.equals(mMagnificationRegion);
699 if (magnifiedChanged) {
700 mWindow.setBounds(mMagnificationRegion);
701 final Rect dirtyRect = mTempRect1;
702 if (mFullRedrawNeeded) {
703 mFullRedrawNeeded = false;
704 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
705 screenWidth - mDrawBorderInset,
706 screenHeight - mDrawBorderInset);
707 mWindow.invalidate(dirtyRect);
708 } else {
709 final Region dirtyRegion = mTempRegion3;
710 dirtyRegion.set(mMagnificationRegion);
711 dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
712 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
713 dirtyRegion.getBounds(dirtyRect);
714 mWindow.invalidate(dirtyRect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800715 }
716
Phil Weaver70439242016-03-10 15:15:49 -0800717 mOldMagnificationRegion.set(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500718 final SomeArgs args = SomeArgs.obtain();
Phil Weaver70439242016-03-10 15:15:49 -0800719 args.arg1 = Region.obtain(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500720 mHandler.obtainMessage(
Phil Weaver70439242016-03-10 15:15:49 -0800721 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
722 .sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800723 }
724 }
725
Jackal Guoc2e12c42019-02-27 17:06:33 +0800726 private Region getLetterboxBounds(WindowState windowState) {
727 final AppWindowToken appToken = windowState.mAppToken;
728 if (appToken == null) {
729 return new Region();
730 }
731
732 mDisplay.getRealSize(mTempPoint);
733 final Rect letterboxInsets = appToken.getLetterboxInsets();
734 final int screenWidth = mTempPoint.x;
735 final int screenHeight = mTempPoint.y;
736 final Rect nonLetterboxRect = mTempRect1;
737 final Region letterboxBounds = mTempRegion3;
738 nonLetterboxRect.set(0, 0, screenWidth, screenHeight);
739 nonLetterboxRect.inset(letterboxInsets);
740 letterboxBounds.set(0, 0, screenWidth, screenHeight);
741 letterboxBounds.op(nonLetterboxRect, Region.Op.DIFFERENCE);
742 return letterboxBounds;
743 }
744
Svetoslav8e3feb12014-02-24 13:46:47 -0800745 public void onRotationChangedLocked() {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800746 // If we are showing the magnification border, hide it immediately so
Svetoslav8e3feb12014-02-24 13:46:47 -0800747 // the user does not see strange artifacts during rotation. The screenshot
Casey Burkhardt74922c62017-02-13 12:43:16 -0800748 // used for rotation already has the border. After the rotation is complete
Svetoslav8e3feb12014-02-24 13:46:47 -0800749 // we will show the border.
Casey Burkhardt74922c62017-02-13 12:43:16 -0800750 if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800751 setMagnifiedRegionBorderShownLocked(false, false);
752 final long delay = (long) (mLongAnimationDuration
Robert Carre625fcf2017-09-01 12:36:28 -0700753 * mService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800754 Message message = mHandler.obtainMessage(
755 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
756 mHandler.sendMessageDelayed(message, delay);
757 }
758 recomputeBoundsLocked();
759 mWindow.updateSize();
760 }
761
762 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
763 if (shown) {
764 mFullRedrawNeeded = true;
Phil Weaver70439242016-03-10 15:15:49 -0800765 mOldMagnificationRegion.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800766 }
767 mWindow.setShown(shown, animate);
768 }
769
770 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
771 MagnificationSpec spec = mMagnificationSpec;
Phil Weaver70439242016-03-10 15:15:49 -0800772 mMagnificationRegion.getBounds(rect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800773 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
774 rect.scale(1.0f / spec.scale);
775 }
776
777 public boolean isMagnifyingLocked() {
778 return mMagnificationSpec.scale > 1.0f;
779 }
780
781 public MagnificationSpec getMagnificationSpecLocked() {
782 return mMagnificationSpec;
783 }
784
785 /** NOTE: This has to be called within a surface transaction. */
786 public void drawWindowIfNeededLocked() {
787 recomputeBoundsLocked();
788 mWindow.drawIfNeeded();
789 }
790
791 public void destroyWindow() {
792 mWindow.releaseSurface();
793 }
794
795 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Robert Carrb1579c82017-09-05 14:54:47 -0700796 mTempLayer = 0;
Rhed Jao02655dc2018-10-30 20:44:52 +0800797 mDisplayContent.forAllWindows((w) -> {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800798 if (w.isOnScreen() && w.isVisibleLw()
Phil Weaverd6ce7372018-05-18 09:48:01 -0700799 && (w.mAttrs.alpha != 0)
Wale Ogunwaled1880962016-11-08 10:31:59 -0800800 && !w.mWinAnimator.mEnterAnimationPending) {
Robert Carrb1579c82017-09-05 14:54:47 -0700801 mTempLayer++;
802 outWindows.put(mTempLayer, w);
Svetoslav8e3feb12014-02-24 13:46:47 -0800803 }
Wale Ogunwaled1880962016-11-08 10:31:59 -0800804 }, false /* traverseTopToBottom */ );
Svetoslav8e3feb12014-02-24 13:46:47 -0800805 }
806
807 private final class ViewportWindow {
808 private static final String SURFACE_TITLE = "Magnification Overlay";
809
Svetoslav8e3feb12014-02-24 13:46:47 -0800810 private final Region mBounds = new Region();
811 private final Rect mDirtyRect = new Rect();
812 private final Paint mPaint = new Paint();
813
Svetoslav8e3feb12014-02-24 13:46:47 -0800814 private final SurfaceControl mSurfaceControl;
815 private final Surface mSurface = new Surface();
816
Svet Ganovb21df802014-09-01 19:06:33 -0700817 private final AnimationController mAnimationController;
818
Svetoslav8e3feb12014-02-24 13:46:47 -0800819 private boolean mShown;
820 private int mAlpha;
821
822 private boolean mInvalidated;
823
824 public ViewportWindow(Context context) {
825 SurfaceControl surfaceControl = null;
826 try {
Rhed Jao02655dc2018-10-30 20:44:52 +0800827 mDisplay.getRealSize(mTempPoint);
828 surfaceControl = mDisplayContent
829 .makeOverlay()
Robert Carre625fcf2017-09-01 12:36:28 -0700830 .setName(SURFACE_TITLE)
Vishnu Naire86bd982018-11-28 13:23:17 -0800831 .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo
Robert Carre625fcf2017-09-01 12:36:28 -0700832 .setFormat(PixelFormat.TRANSLUCENT)
833 .build();
Svetoslav8e3feb12014-02-24 13:46:47 -0800834 } catch (OutOfResourcesException oore) {
835 /* ignore */
836 }
837 mSurfaceControl = surfaceControl;
Robert Carre625fcf2017-09-01 12:36:28 -0700838 mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
Phil Weaverd321075e2017-06-13 09:13:35 -0700839 TYPE_MAGNIFICATION_OVERLAY)
Svetoslav8e3feb12014-02-24 13:46:47 -0800840 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
841 mSurfaceControl.setPosition(0, 0);
842 mSurface.copyFrom(mSurfaceControl);
843
Svet Ganovb21df802014-09-01 19:06:33 -0700844 mAnimationController = new AnimationController(context,
Robert Carre625fcf2017-09-01 12:36:28 -0700845 mService.mH.getLooper());
Svet Ganovb21df802014-09-01 19:06:33 -0700846
Svetoslav8e3feb12014-02-24 13:46:47 -0800847 TypedValue typedValue = new TypedValue();
848 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
849 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700850 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800851
852 mPaint.setStyle(Paint.Style.STROKE);
853 mPaint.setStrokeWidth(mBorderWidth);
854 mPaint.setColor(borderColor);
855
Svetoslav8e3feb12014-02-24 13:46:47 -0800856 mInvalidated = true;
857 }
858
859 public void setShown(boolean shown, boolean animate) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700860 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800861 if (mShown == shown) {
862 return;
863 }
864 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700865 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800866 if (DEBUG_VIEWPORT_WINDOW) {
867 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
868 }
869 }
870 }
871
872 @SuppressWarnings("unused")
873 // Called reflectively from an animator.
874 public int getAlpha() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700875 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800876 return mAlpha;
877 }
878 }
879
880 public void setAlpha(int alpha) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700881 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800882 if (mAlpha == alpha) {
883 return;
884 }
885 mAlpha = alpha;
886 invalidate(null);
887 if (DEBUG_VIEWPORT_WINDOW) {
888 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
889 }
890 }
891 }
892
893 public void setBounds(Region bounds) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700894 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800895 if (mBounds.equals(bounds)) {
896 return;
897 }
898 mBounds.set(bounds);
899 invalidate(mDirtyRect);
900 if (DEBUG_VIEWPORT_WINDOW) {
901 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
902 }
903 }
904 }
905
906 public void updateSize() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700907 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800908 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
Vishnu Naire86bd982018-11-28 13:23:17 -0800909 mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y);
Svetoslav8e3feb12014-02-24 13:46:47 -0800910 invalidate(mDirtyRect);
911 }
912 }
913
914 public void invalidate(Rect dirtyRect) {
915 if (dirtyRect != null) {
916 mDirtyRect.set(dirtyRect);
917 } else {
918 mDirtyRect.setEmpty();
919 }
920 mInvalidated = true;
Robert Carre625fcf2017-09-01 12:36:28 -0700921 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800922 }
923
924 /** NOTE: This has to be called within a surface transaction. */
925 public void drawIfNeeded() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700926 synchronized (mService.mGlobalLock) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800927 if (!mInvalidated) {
928 return;
929 }
930 mInvalidated = false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800931 if (mAlpha > 0) {
Adrian Roos69364f52018-04-19 18:49:39 +0200932 Canvas canvas = null;
933 try {
934 // Empty dirty rectangle means unspecified.
935 if (mDirtyRect.isEmpty()) {
936 mBounds.getBounds(mDirtyRect);
937 }
938 mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
939 canvas = mSurface.lockCanvas(mDirtyRect);
940 if (DEBUG_VIEWPORT_WINDOW) {
941 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
942 }
943 } catch (IllegalArgumentException iae) {
944 /* ignore */
945 } catch (Surface.OutOfResourcesException oore) {
946 /* ignore */
947 }
948 if (canvas == null) {
949 return;
950 }
951 if (DEBUG_VIEWPORT_WINDOW) {
952 Slog.i(LOG_TAG, "Bounds: " + mBounds);
953 }
954 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
955 mPaint.setAlpha(mAlpha);
956 Path path = mBounds.getBoundaryPath();
957 canvas.drawPath(path, mPaint);
958
959 mSurface.unlockCanvasAndPost(canvas);
Svetoslav8e3feb12014-02-24 13:46:47 -0800960 mSurfaceControl.show();
961 } else {
962 mSurfaceControl.hide();
963 }
964 }
965 }
966
967 public void releaseSurface() {
chaviw9f6171e2019-06-07 16:33:50 -0700968 mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
Svetoslav8e3feb12014-02-24 13:46:47 -0800969 mSurface.release();
970 }
Svet Ganovb21df802014-09-01 19:06:33 -0700971
972 private final class AnimationController extends Handler {
973 private static final String PROPERTY_NAME_ALPHA = "alpha";
974
975 private static final int MIN_ALPHA = 0;
976 private static final int MAX_ALPHA = 255;
977
978 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
979
980 private final ValueAnimator mShowHideFrameAnimator;
981
982 public AnimationController(Context context, Looper looper) {
983 super(looper);
984 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
985 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
986
987 Interpolator interpolator = new DecelerateInterpolator(2.5f);
988 final long longAnimationDuration = context.getResources().getInteger(
989 com.android.internal.R.integer.config_longAnimTime);
990
991 mShowHideFrameAnimator.setInterpolator(interpolator);
992 mShowHideFrameAnimator.setDuration(longAnimationDuration);
993 }
994
995 public void onFrameShownStateChanged(boolean shown, boolean animate) {
996 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
997 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
998 }
999
1000 @Override
1001 public void handleMessage(Message message) {
1002 switch (message.what) {
1003 case MSG_FRAME_SHOWN_STATE_CHANGED: {
1004 final boolean shown = message.arg1 == 1;
1005 final boolean animate = message.arg2 == 1;
1006
1007 if (animate) {
1008 if (mShowHideFrameAnimator.isRunning()) {
1009 mShowHideFrameAnimator.reverse();
1010 } else {
1011 if (shown) {
1012 mShowHideFrameAnimator.start();
1013 } else {
1014 mShowHideFrameAnimator.reverse();
1015 }
1016 }
1017 } else {
1018 mShowHideFrameAnimator.cancel();
1019 if (shown) {
1020 setAlpha(MAX_ALPHA);
1021 } else {
1022 setAlpha(MIN_ALPHA);
1023 }
1024 }
1025 } break;
1026 }
1027 }
1028 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001029 }
1030 }
1031
1032 private class MyHandler extends Handler {
Phil Weaver70439242016-03-10 15:15:49 -08001033 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001034 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
1035 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
1036 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
1037 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
1038
1039 public MyHandler(Looper looper) {
1040 super(looper);
1041 }
1042
1043 @Override
1044 public void handleMessage(Message message) {
1045 switch (message.what) {
Phil Weaver70439242016-03-10 15:15:49 -08001046 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -05001047 final SomeArgs args = (SomeArgs) message.obj;
1048 final Region magnifiedBounds = (Region) args.arg1;
Phil Weaver70439242016-03-10 15:15:49 -08001049 mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -05001050 magnifiedBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -08001051 } break;
1052
1053 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
1054 SomeArgs args = (SomeArgs) message.obj;
1055 final int left = args.argi1;
1056 final int top = args.argi2;
1057 final int right = args.argi3;
1058 final int bottom = args.argi4;
1059 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
1060 args.recycle();
1061 } break;
1062
1063 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
1064 mCallbacks.onUserContextChanged();
1065 } break;
1066
1067 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
1068 final int rotation = message.arg1;
1069 mCallbacks.onRotationChanged(rotation);
1070 } break;
1071
1072 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001073 synchronized (mService.mGlobalLock) {
Casey Burkhardt74922c62017-02-13 12:43:16 -08001074 if (mMagnifedViewport.isMagnifyingLocked()
1075 || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001076 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
Robert Carre625fcf2017-09-01 12:36:28 -07001077 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -08001078 }
1079 }
1080 } break;
1081 }
1082 }
1083 }
1084 }
1085
1086 /**
1087 * This class encapsulates the functionality related to computing the windows
1088 * reported for accessibility purposes. These windows are all windows a sighted
1089 * user can see on the screen.
1090 */
1091 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -08001092 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
1093 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -08001094
1095 private static final boolean DEBUG = false;
1096
Jackal Guo28dce102019-05-28 14:25:17 +08001097 private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001098
Jackal Guo28dce102019-05-28 14:25:17 +08001099 private final Set<IBinder> mTempBinderSet = new ArraySet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001100
1101 private final RectF mTempRectF = new RectF();
1102
1103 private final Matrix mTempMatrix = new Matrix();
1104
1105 private final Point mTempPoint = new Point();
1106
1107 private final Rect mTempRect = new Rect();
1108
1109 private final Region mTempRegion = new Region();
1110
1111 private final Region mTempRegion1 = new Region();
1112
1113 private final Context mContext;
1114
Robert Carre625fcf2017-09-01 12:36:28 -07001115 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001116
1117 private final Handler mHandler;
1118
1119 private final WindowsForAccessibilityCallback mCallback;
1120
Jacky Kaof93252b2019-07-18 15:19:52 +08001121 private final int mDisplayId;
1122
Svetoslavf7174e82014-06-12 11:29:35 -07001123 private final long mRecurringAccessibilityEventsIntervalMillis;
1124
Svetoslav8e3feb12014-02-24 13:46:47 -08001125 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
Jacky Kaof93252b2019-07-18 15:19:52 +08001126 int displayId,
Svetoslav8e3feb12014-02-24 13:46:47 -08001127 WindowsForAccessibilityCallback callback) {
1128 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -07001129 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001130 mCallback = callback;
Jacky Kaof93252b2019-07-18 15:19:52 +08001131 mDisplayId = displayId;
Robert Carre625fcf2017-09-01 12:36:28 -07001132 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -07001133 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1134 .getSendRecurringAccessibilityEventsInterval();
Phil Weaverc72faad2018-07-24 10:53:01 -07001135 computeChangedWindows(true);
Svetoslav8e3feb12014-02-24 13:46:47 -08001136 }
1137
Phil Weaverc72faad2018-07-24 10:53:01 -07001138 public void performComputeChangedWindowsNotLocked(boolean forceSend) {
Svetoslav3a0d8782014-12-04 12:50:11 -08001139 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
Phil Weaverc72faad2018-07-24 10:53:01 -07001140 computeChangedWindows(forceSend);
Svetoslav3a0d8782014-12-04 12:50:11 -08001141 }
1142
Svetoslavf7174e82014-06-12 11:29:35 -07001143 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -08001144 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001145 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1146 mRecurringAccessibilityEventsIntervalMillis);
1147 }
1148 }
1149
Phil Weaverc72faad2018-07-24 10:53:01 -07001150 /**
Jackal Guoc43a0a62019-04-23 09:15:14 +08001151 * Check if windows have changed, and send them to the accessibility subsystem if they have.
Phil Weaverc72faad2018-07-24 10:53:01 -07001152 *
1153 * @param forceSend Send the windows the accessibility even if they haven't changed.
1154 */
1155 public void computeChangedWindows(boolean forceSend) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001156 if (DEBUG) {
1157 Slog.i(LOG_TAG, "computeChangedWindows()");
1158 }
1159
Jackal Guo28dce102019-05-28 14:25:17 +08001160 List<WindowInfo> windows = new ArrayList<>();
Svetoslav3a0d8782014-12-04 12:50:11 -08001161
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001162 synchronized (mService.mGlobalLock) {
Svetoslavf7174e82014-06-12 11:29:35 -07001163 // Do not send the windows if there is no current focus as
1164 // the window manager is still looking for where to put it.
1165 // We will do the work when we get a focus change callback.
Jacky Kaof93252b2019-07-18 15:19:52 +08001166 // TODO [Multi-Display] : only checks top focused window
Jackal Guoc43a0a62019-04-23 09:15:14 +08001167 if (!isCurrentFocusWindowOnDefaultDisplay()) {
Svetoslavf7174e82014-06-12 11:29:35 -07001168 return;
1169 }
1170
Jacky Kaof93252b2019-07-18 15:19:52 +08001171 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
1172 if (dc == null) {
1173 return;
1174 }
1175 final Display display = dc.getDisplay();
1176 display.getRealSize(mTempPoint);
Svetoslav8e3feb12014-02-24 13:46:47 -08001177 final int screenWidth = mTempPoint.x;
1178 final int screenHeight = mTempPoint.y;
1179
1180 Region unaccountedSpace = mTempRegion;
1181 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1182
Wale Ogunwalef7cab102016-10-25 15:25:14 -07001183 final SparseArray<WindowState> visibleWindows = mTempWindowStates;
Svetoslav8e3feb12014-02-24 13:46:47 -08001184 populateVisibleWindowsOnScreenLocked(visibleWindows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001185 Set<IBinder> addedWindows = mTempBinderSet;
1186 addedWindows.clear();
1187
Svetoslavf7174e82014-06-12 11:29:35 -07001188 boolean focusedWindowAdded = false;
1189
Svetoslav8e3feb12014-02-24 13:46:47 -08001190 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001191 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001192
1193 // Iterate until we figure out what is touchable for the entire screen.
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001194 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001195 final WindowState windowState = visibleWindows.valueAt(i);
Jackal Guof3823712019-05-20 10:16:06 +08001196 final Region regionInScreen = new Region();
1197 computeWindowRegionInScreen(windowState, regionInScreen);
Allen Hairf20ac2c2016-02-11 17:42:59 -08001198
Jackal Guof3823712019-05-20 10:16:06 +08001199 if (windowMattersToAccessibility(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001200 skipRemainingWindowsForTasks)) {
Jackal Guof3823712019-05-20 10:16:06 +08001201 addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows);
1202 updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace,
Qasid Ahmad Sadiq5e1c1ca2019-01-03 21:55:55 -08001203 skipRemainingWindowsForTasks);
Qasid Ahmad Sadiqd98cedd2019-04-12 21:56:24 +08001204 focusedWindowAdded |= windowState.isFocused();
1205 }
1206
1207 if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
1208 break;
Svetoslavf7174e82014-06-12 11:29:35 -07001209 }
1210 }
1211
Svetoslav8e3feb12014-02-24 13:46:47 -08001212 // Remove child/parent references to windows that were not added.
1213 final int windowCount = windows.size();
1214 for (int i = 0; i < windowCount; i++) {
1215 WindowInfo window = windows.get(i);
1216 if (!addedWindows.contains(window.parentToken)) {
1217 window.parentToken = null;
1218 }
1219 if (window.childTokens != null) {
1220 final int childTokenCount = window.childTokens.size();
1221 for (int j = childTokenCount - 1; j >= 0; j--) {
1222 if (!addedWindows.contains(window.childTokens.get(j))) {
1223 window.childTokens.remove(j);
1224 }
1225 }
1226 // Leave the child token list if empty.
1227 }
1228 }
1229
1230 visibleWindows.clear();
1231 addedWindows.clear();
Svetoslav8e3feb12014-02-24 13:46:47 -08001232 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001233
Jackal Guo28dce102019-05-28 14:25:17 +08001234 mCallback.onWindowsForAccessibilityChanged(forceSend, 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 }
Jacky Kaof93252b2019-07-18 15:19:52 +08001413 // TODO [Multi-Display] : only checks top focused window
Jackal Guoc43a0a62019-04-23 09:15:14 +08001414 private boolean isCurrentFocusWindowOnDefaultDisplay() {
1415 final WindowState focusedWindow =
1416 mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
1417 if (focusedWindow == null) {
1418 return false;
1419 }
1420
1421 final WindowState rootDisplayParentWindow = findRootDisplayParentWindow(focusedWindow);
1422 if (!focusedWindow.isDefaultDisplay()
1423 && (rootDisplayParentWindow == null
1424 || !rootDisplayParentWindow.isDefaultDisplay())) {
1425 return false;
1426 }
1427
1428 return true;
1429 }
1430
Svetoslav8e3feb12014-02-24 13:46:47 -08001431 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001432 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001433
1434 public MyHandler(Looper looper) {
1435 super(looper, null, false);
1436 }
1437
1438 @Override
1439 @SuppressWarnings("unchecked")
1440 public void handleMessage(Message message) {
1441 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001442 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
Phil Weaverc72faad2018-07-24 10:53:01 -07001443 computeChangedWindows(false);
Svetoslavf7174e82014-06-12 11:29:35 -07001444 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001445 }
1446 }
1447 }
1448 }
1449}