blob: 68be50c2689a78526926d50de39bdbe81b0435ce [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
Phil Weaverb2779532017-12-18 17:09:32 -080019import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
Phil Weaverd321075e2017-06-13 09:13:35 -070020import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
Robert Carr132c9f52017-07-31 17:02:30 -070021import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_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;
25
Svetoslav8e3feb12014-02-24 13:46:47 -080026import android.animation.ObjectAnimator;
27import android.animation.ValueAnimator;
Alan Viverette59e53a12016-03-28 13:41:32 -040028import android.annotation.NonNull;
Svetoslav8e3feb12014-02-24 13:46:47 -080029import android.app.Service;
30import android.content.Context;
31import android.graphics.Canvas;
32import android.graphics.Color;
33import android.graphics.Matrix;
34import android.graphics.Paint;
35import android.graphics.Path;
36import android.graphics.PixelFormat;
37import android.graphics.Point;
38import android.graphics.PorterDuff.Mode;
39import android.graphics.Rect;
40import android.graphics.RectF;
41import android.graphics.Region;
42import android.os.Handler;
43import android.os.IBinder;
44import android.os.Looper;
45import android.os.Message;
Phil Weaver396d5492016-03-22 17:53:50 -070046import android.text.TextUtils;
Svetoslav8e3feb12014-02-24 13:46:47 -080047import android.util.ArraySet;
48import android.util.Log;
49import android.util.Slog;
50import android.util.SparseArray;
51import android.util.TypedValue;
52import 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/**
74 * This class contains the accessibility related logic of the window manger.
75 */
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
86 private DisplayMagnifier mDisplayMagnifier;
87
88 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
89
Phil Weaverd7551602018-02-15 15:01:04 -080090 private boolean mScreenMagnificationActive;
91
Svetoslav8e3feb12014-02-24 13:46:47 -080092 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
93 if (callbacks != null) {
94 if (mDisplayMagnifier != null) {
95 throw new IllegalStateException("Magnification callbacks already set!");
96 }
Robert Carre625fcf2017-09-01 12:36:28 -070097 mDisplayMagnifier = new DisplayMagnifier(mService, callbacks);
Svetoslav8e3feb12014-02-24 13:46:47 -080098 } else {
99 if (mDisplayMagnifier == null) {
100 throw new IllegalStateException("Magnification callbacks already cleared!");
101 }
102 mDisplayMagnifier.destroyLocked();
103 mDisplayMagnifier = null;
104 }
105 }
106
107 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
108 if (callback != null) {
109 if (mWindowsForAccessibilityObserver != null) {
110 throw new IllegalStateException(
111 "Windows for accessibility callback already set!");
112 }
113 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
Robert Carre625fcf2017-09-01 12:36:28 -0700114 mService, callback);
Svetoslav8e3feb12014-02-24 13:46:47 -0800115 } else {
116 if (mWindowsForAccessibilityObserver == null) {
117 throw new IllegalStateException(
118 "Windows for accessibility callback already cleared!");
119 }
120 mWindowsForAccessibilityObserver = null;
121 }
122 }
123
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700124 public void performComputeChangedWindowsNotLocked() {
125 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700126 synchronized (mService) {
Svetoslav Ganovfd138892016-07-13 18:20:42 -0700127 observer = mWindowsForAccessibilityObserver;
128 }
129 if (observer != null) {
130 observer.performComputeChangedWindowsNotLocked();
131 }
132 }
133
Svetoslav8e3feb12014-02-24 13:46:47 -0800134 public void setMagnificationSpecLocked(MagnificationSpec spec) {
135 if (mDisplayMagnifier != null) {
136 mDisplayMagnifier.setMagnificationSpecLocked(spec);
137 }
138 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700139 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800140 }
Phil Weaverd7551602018-02-15 15:01:04 -0800141 boolean nowActive = !spec.isNop();
142 if (nowActive != mScreenMagnificationActive) {
143 mScreenMagnificationActive = nowActive;
144 mService.mPolicy.onScreenMagnificationStateChanged(nowActive);
145 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800146 }
147
Phil Weaver70439242016-03-10 15:15:49 -0800148 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400149 if (mDisplayMagnifier != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800150 mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400151 }
152 }
153
Svetoslavf7174e82014-06-12 11:29:35 -0700154 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800155 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700156 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800157 }
158 // Not relevant for the window observer.
159 }
160
161 public void onWindowLayersChangedLocked() {
162 if (mDisplayMagnifier != null) {
163 mDisplayMagnifier.onWindowLayersChangedLocked();
164 }
165 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700166 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800167 }
168 }
169
Andrii Kulian8ee72852017-03-10 10:36:45 -0800170 public void onRotationChangedLocked(DisplayContent displayContent) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800171 if (mDisplayMagnifier != null) {
Andrii Kulian8ee72852017-03-10 10:36:45 -0800172 mDisplayMagnifier.onRotationChangedLocked(displayContent);
Svetoslav8e3feb12014-02-24 13:46:47 -0800173 }
174 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700175 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800176 }
177 }
178
179 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
180 if (mDisplayMagnifier != null) {
181 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
182 }
183 // Not relevant for the window observer.
184 }
185
186 public void onWindowTransitionLocked(WindowState windowState, int transition) {
187 if (mDisplayMagnifier != null) {
188 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
189 }
190 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700191 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800192 }
193 }
194
Svetoslav3a0d8782014-12-04 12:50:11 -0800195 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800196 // Not relevant for the display magnifier.
197
Svetoslav3a0d8782014-12-04 12:50:11 -0800198 WindowsForAccessibilityObserver observer = null;
Robert Carre625fcf2017-09-01 12:36:28 -0700199 synchronized (mService) {
Svetoslav3a0d8782014-12-04 12:50:11 -0800200 observer = mWindowsForAccessibilityObserver;
201 }
202 if (observer != null) {
203 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800204 }
205 }
206
Svetoslav4604abc2014-06-10 18:59:30 -0700207
Svetoslavf7174e82014-06-12 11:29:35 -0700208 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700209 // Not relevant for the display magnifier.
210
211 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700212 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700213 }
214 }
215
Svetoslav8e3feb12014-02-24 13:46:47 -0800216 /** NOTE: This has to be called within a surface transaction. */
217 public void drawMagnifiedRegionBorderIfNeededLocked() {
218 if (mDisplayMagnifier != null) {
219 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
220 }
221 // Not relevant for the window observer.
222 }
223
224 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
225 if (mDisplayMagnifier != null) {
226 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
227 }
228 return null;
229 }
230
231 public boolean hasCallbacksLocked() {
232 return (mDisplayMagnifier != null
233 || mWindowsForAccessibilityObserver != null);
234 }
235
Casey Burkhardt74922c62017-02-13 12:43:16 -0800236 public void setForceShowMagnifiableBoundsLocked(boolean show) {
237 if (mDisplayMagnifier != null) {
238 mDisplayMagnifier.setForceShowMagnifiableBoundsLocked(show);
Phil Weaver251db072017-03-28 08:35:38 -0700239 mDisplayMagnifier.showMagnificationBoundsIfNeeded();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800240 }
241 }
242
Svetoslav8e3feb12014-02-24 13:46:47 -0800243 private static void populateTransformationMatrixLocked(WindowState windowState,
244 Matrix outMatrix) {
Jorim Jaggieb0d3bc2017-12-15 14:56:19 +0100245 windowState.getTransformationMatrix(sTempFloats, outMatrix);
Svetoslav8e3feb12014-02-24 13:46:47 -0800246 }
247
248 /**
249 * This class encapsulates the functionality related to display magnification.
250 */
251 private static final class DisplayMagnifier {
252
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800253 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800254
255 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
256 private static final boolean DEBUG_ROTATION = false;
257 private static final boolean DEBUG_LAYERS = false;
258 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
259 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
260
261 private final Rect mTempRect1 = new Rect();
262 private final Rect mTempRect2 = new Rect();
263
264 private final Region mTempRegion1 = new Region();
265 private final Region mTempRegion2 = new Region();
266 private final Region mTempRegion3 = new Region();
267 private final Region mTempRegion4 = new Region();
268
269 private final Context mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700270 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800271 private final MagnifiedViewport mMagnifedViewport;
272 private final Handler mHandler;
273
274 private final MagnificationCallbacks mCallbacks;
275
276 private final long mLongAnimationDuration;
277
Casey Burkhardt74922c62017-02-13 12:43:16 -0800278 private boolean mForceShowMagnifiableBounds = false;
279
Svetoslav8e3feb12014-02-24 13:46:47 -0800280 public DisplayMagnifier(WindowManagerService windowManagerService,
281 MagnificationCallbacks callbacks) {
282 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -0700283 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -0800284 mCallbacks = callbacks;
Robert Carre625fcf2017-09-01 12:36:28 -0700285 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslav8e3feb12014-02-24 13:46:47 -0800286 mMagnifedViewport = new MagnifiedViewport();
287 mLongAnimationDuration = mContext.getResources().getInteger(
288 com.android.internal.R.integer.config_longAnimTime);
289 }
290
291 public void setMagnificationSpecLocked(MagnificationSpec spec) {
292 mMagnifedViewport.updateMagnificationSpecLocked(spec);
293 mMagnifedViewport.recomputeBoundsLocked();
Robert Carrb1579c82017-09-05 14:54:47 -0700294
295 mService.applyMagnificationSpec(spec);
Robert Carre625fcf2017-09-01 12:36:28 -0700296 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800297 }
298
Casey Burkhardt74922c62017-02-13 12:43:16 -0800299 public void setForceShowMagnifiableBoundsLocked(boolean show) {
300 mForceShowMagnifiableBounds = show;
301 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
302 }
303
304 public boolean isForceShowingMagnifiableBoundsLocked() {
305 return mForceShowMagnifiableBounds;
306 }
307
Svetoslavf7174e82014-06-12 11:29:35 -0700308 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800309 if (DEBUG_RECTANGLE_REQUESTED) {
310 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
311 }
312 if (!mMagnifedViewport.isMagnifyingLocked()) {
313 return;
314 }
315 Rect magnifiedRegionBounds = mTempRect2;
316 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
317 if (magnifiedRegionBounds.contains(rectangle)) {
318 return;
319 }
320 SomeArgs args = SomeArgs.obtain();
321 args.argi1 = rectangle.left;
322 args.argi2 = rectangle.top;
323 args.argi3 = rectangle.right;
324 args.argi4 = rectangle.bottom;
325 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
326 args).sendToTarget();
327 }
328
329 public void onWindowLayersChangedLocked() {
330 if (DEBUG_LAYERS) {
331 Slog.i(LOG_TAG, "Layers changed.");
332 }
333 mMagnifedViewport.recomputeBoundsLocked();
Robert Carre625fcf2017-09-01 12:36:28 -0700334 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800335 }
336
Andrii Kulian8ee72852017-03-10 10:36:45 -0800337 public void onRotationChangedLocked(DisplayContent displayContent) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800338 if (DEBUG_ROTATION) {
Andrii Kulian8ee72852017-03-10 10:36:45 -0800339 final int rotation = displayContent.getRotation();
340 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
Svetoslav8e3feb12014-02-24 13:46:47 -0800341 + " displayId: " + displayContent.getDisplayId());
342 }
343 mMagnifedViewport.onRotationChangedLocked();
344 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
345 }
346
347 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
348 if (DEBUG_WINDOW_TRANSITIONS) {
349 Slog.i(LOG_TAG, "Window transition: "
350 + AppTransition.appTransitionToString(transition)
351 + " displayId: " + windowState.getDisplayId());
352 }
353 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
354 if (magnifying) {
355 switch (transition) {
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100356 case WindowManager.TRANSIT_ACTIVITY_OPEN:
357 case WindowManager.TRANSIT_TASK_OPEN:
358 case WindowManager.TRANSIT_TASK_TO_FRONT:
359 case WindowManager.TRANSIT_WALLPAPER_OPEN:
360 case WindowManager.TRANSIT_WALLPAPER_CLOSE:
361 case WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800362 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
363 }
364 }
365 }
366 }
367
368 public void onWindowTransitionLocked(WindowState windowState, int transition) {
369 if (DEBUG_WINDOW_TRANSITIONS) {
370 Slog.i(LOG_TAG, "Window transition: "
371 + AppTransition.appTransitionToString(transition)
372 + " displayId: " + windowState.getDisplayId());
373 }
374 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
375 final int type = windowState.mAttrs.type;
376 switch (transition) {
377 case WindowManagerPolicy.TRANSIT_ENTER:
378 case WindowManagerPolicy.TRANSIT_SHOW: {
379 if (!magnifying) {
380 break;
381 }
382 switch (type) {
383 case WindowManager.LayoutParams.TYPE_APPLICATION:
Chong Zhangfea963e2016-08-15 17:14:16 -0700384 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
Svetoslav8e3feb12014-02-24 13:46:47 -0800385 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
386 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
387 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700388 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800389 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
390 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
391 case WindowManager.LayoutParams.TYPE_PHONE:
392 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
393 case WindowManager.LayoutParams.TYPE_TOAST:
394 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800395 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
Svetoslav8e3feb12014-02-24 13:46:47 -0800396 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
397 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
398 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
399 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
400 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500401 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200402 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800403 Rect magnifiedRegionBounds = mTempRect2;
404 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
405 magnifiedRegionBounds);
406 Rect touchableRegionBounds = mTempRect1;
407 windowState.getTouchableRegion(mTempRegion1);
408 mTempRegion1.getBounds(touchableRegionBounds);
409 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
410 mCallbacks.onRectangleOnScreenRequested(
411 touchableRegionBounds.left,
412 touchableRegionBounds.top,
413 touchableRegionBounds.right,
414 touchableRegionBounds.bottom);
415 }
416 } break;
417 } break;
418 }
419 }
420 }
421
422 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
423 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
424 if (spec != null && !spec.isNop()) {
Robert Carrb1579c82017-09-05 14:54:47 -0700425 if (!windowState.shouldMagnify()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800426 return null;
427 }
428 }
429 return spec;
430 }
431
Phil Weaver70439242016-03-10 15:15:49 -0800432 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Phil Weaver53b690b2017-08-14 17:42:39 -0700433 // Make sure we're working with the most current bounds
434 mMagnifedViewport.recomputeBoundsLocked();
Phil Weaver70439242016-03-10 15:15:49 -0800435 mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400436 }
437
Svetoslav8e3feb12014-02-24 13:46:47 -0800438 public void destroyLocked() {
439 mMagnifedViewport.destroyWindow();
440 }
441
Phil Weaver251db072017-03-28 08:35:38 -0700442 // Can be called outside of a surface transaction
443 public void showMagnificationBoundsIfNeeded() {
444 mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
445 .sendToTarget();
446 }
447
Svetoslav8e3feb12014-02-24 13:46:47 -0800448 /** NOTE: This has to be called within a surface transaction. */
449 public void drawMagnifiedRegionBorderIfNeededLocked() {
450 mMagnifedViewport.drawWindowIfNeededLocked();
451 }
452
453 private final class MagnifiedViewport {
454
Svetoslav8e3feb12014-02-24 13:46:47 -0800455 private final SparseArray<WindowState> mTempWindowStates =
456 new SparseArray<WindowState>();
457
458 private final RectF mTempRectF = new RectF();
459
460 private final Point mTempPoint = new Point();
461
462 private final Matrix mTempMatrix = new Matrix();
463
Phil Weaver70439242016-03-10 15:15:49 -0800464 private final Region mMagnificationRegion = new Region();
465 private final Region mOldMagnificationRegion = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800466
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800467 private final Path mCircularPath;
468
Svetoslav8e3feb12014-02-24 13:46:47 -0800469 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
470
471 private final WindowManager mWindowManager;
472
Svetoslav7505e332014-08-22 12:14:28 -0700473 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800474 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700475 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800476
477 private final ViewportWindow mWindow;
478
479 private boolean mFullRedrawNeeded;
Robert Carrb1579c82017-09-05 14:54:47 -0700480 private int mTempLayer = 0;
Svetoslav8e3feb12014-02-24 13:46:47 -0800481
482 public MagnifiedViewport() {
483 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800484 mBorderWidth = mContext.getResources().getDimension(
485 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700486 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
487 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800488 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800489
Adam Powell01f280d2015-05-18 16:07:42 -0700490 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800491 mCircularPath = new Path();
492 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
493 final int centerXY = mTempPoint.x / 2;
494 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
495 } else {
496 mCircularPath = null;
497 }
498
Svetoslav8e3feb12014-02-24 13:46:47 -0800499 recomputeBoundsLocked();
500 }
501
Phil Weaver70439242016-03-10 15:15:49 -0800502 public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
503 outMagnificationRegion.set(mMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400504 }
505
Svetoslav8e3feb12014-02-24 13:46:47 -0800506 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
507 if (spec != null) {
508 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
509 } else {
510 mMagnificationSpec.clear();
511 }
512 // If this message is pending we are in a rotation animation and do not want
513 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700514 if (!mHandler.hasMessages(
515 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800516 setMagnifiedRegionBorderShownLocked(
517 isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
Svetoslav8e3feb12014-02-24 13:46:47 -0800518 }
519 }
520
521 public void recomputeBoundsLocked() {
522 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
523 final int screenWidth = mTempPoint.x;
524 final int screenHeight = mTempPoint.y;
525
Phil Weaver70439242016-03-10 15:15:49 -0800526 mMagnificationRegion.set(0, 0, 0, 0);
527 final Region availableBounds = mTempRegion1;
528 availableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800529
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800530 if (mCircularPath != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800531 availableBounds.setPath(mCircularPath, availableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800532 }
533
Svetoslav8e3feb12014-02-24 13:46:47 -0800534 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700535 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800536
537 SparseArray<WindowState> visibleWindows = mTempWindowStates;
538 visibleWindows.clear();
539 populateWindowsOnScreenLocked(visibleWindows);
540
541 final int visibleWindowCount = visibleWindows.size();
542 for (int i = visibleWindowCount - 1; i >= 0; i--) {
543 WindowState windowState = visibleWindows.valueAt(i);
Phil Weaverd321075e2017-06-13 09:13:35 -0700544 if ((windowState.mAttrs.type == TYPE_MAGNIFICATION_OVERLAY)
545 || ((windowState.mAttrs.privateFlags
Robert Carr132c9f52017-07-31 17:02:30 -0700546 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800547 continue;
548 }
549
Phil Weaver65c06702016-03-15 15:33:46 -0700550 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800551 Matrix matrix = mTempMatrix;
552 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700553 Region touchableRegion = mTempRegion3;
554 windowState.getTouchableRegion(touchableRegion);
555 Rect touchableFrame = mTempRect1;
556 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800557 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700558 windowFrame.set(touchableFrame);
559 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
560 matrix.mapRect(windowFrame);
561 Region windowBounds = mTempRegion2;
562 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
563 (int) windowFrame.right, (int) windowFrame.bottom);
564 // Only update new regions
565 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
Phil Weaver70439242016-03-10 15:15:49 -0800566 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
Phil Weaver65c06702016-03-15 15:33:46 -0700567 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
568 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800569
Robert Carrb1579c82017-09-05 14:54:47 -0700570 if (windowState.shouldMagnify()) {
Phil Weaver70439242016-03-10 15:15:49 -0800571 mMagnificationRegion.op(windowBounds, Region.Op.UNION);
572 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800573 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800574 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Phil Weaver70439242016-03-10 15:15:49 -0800575 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800576 }
577
Phil Weaver65c06702016-03-15 15:33:46 -0700578 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800579 Region accountedBounds = mTempRegion2;
Phil Weaver70439242016-03-10 15:15:49 -0800580 accountedBounds.set(mMagnificationRegion);
Svetoslav8e3feb12014-02-24 13:46:47 -0800581 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
582 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
583
584 if (accountedBounds.isRect()) {
585 Rect accountedFrame = mTempRect1;
586 accountedBounds.getBounds(accountedFrame);
587 if (accountedFrame.width() == screenWidth
588 && accountedFrame.height() == screenHeight) {
589 break;
590 }
591 }
592 }
593
594 visibleWindows.clear();
595
Phil Weaver70439242016-03-10 15:15:49 -0800596 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700597 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800598 Region.Op.INTERSECT);
599
Phil Weaver70439242016-03-10 15:15:49 -0800600 final boolean magnifiedChanged =
601 !mOldMagnificationRegion.equals(mMagnificationRegion);
602 if (magnifiedChanged) {
603 mWindow.setBounds(mMagnificationRegion);
604 final Rect dirtyRect = mTempRect1;
605 if (mFullRedrawNeeded) {
606 mFullRedrawNeeded = false;
607 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
608 screenWidth - mDrawBorderInset,
609 screenHeight - mDrawBorderInset);
610 mWindow.invalidate(dirtyRect);
611 } else {
612 final Region dirtyRegion = mTempRegion3;
613 dirtyRegion.set(mMagnificationRegion);
614 dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
615 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
616 dirtyRegion.getBounds(dirtyRect);
617 mWindow.invalidate(dirtyRect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800618 }
619
Phil Weaver70439242016-03-10 15:15:49 -0800620 mOldMagnificationRegion.set(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500621 final SomeArgs args = SomeArgs.obtain();
Phil Weaver70439242016-03-10 15:15:49 -0800622 args.arg1 = Region.obtain(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500623 mHandler.obtainMessage(
Phil Weaver70439242016-03-10 15:15:49 -0800624 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
625 .sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800626 }
627 }
628
629 public void onRotationChangedLocked() {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800630 // If we are showing the magnification border, hide it immediately so
Svetoslav8e3feb12014-02-24 13:46:47 -0800631 // the user does not see strange artifacts during rotation. The screenshot
Casey Burkhardt74922c62017-02-13 12:43:16 -0800632 // used for rotation already has the border. After the rotation is complete
Svetoslav8e3feb12014-02-24 13:46:47 -0800633 // we will show the border.
Casey Burkhardt74922c62017-02-13 12:43:16 -0800634 if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800635 setMagnifiedRegionBorderShownLocked(false, false);
636 final long delay = (long) (mLongAnimationDuration
Robert Carre625fcf2017-09-01 12:36:28 -0700637 * mService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800638 Message message = mHandler.obtainMessage(
639 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
640 mHandler.sendMessageDelayed(message, delay);
641 }
642 recomputeBoundsLocked();
643 mWindow.updateSize();
644 }
645
646 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
647 if (shown) {
648 mFullRedrawNeeded = true;
Phil Weaver70439242016-03-10 15:15:49 -0800649 mOldMagnificationRegion.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800650 }
651 mWindow.setShown(shown, animate);
652 }
653
654 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
655 MagnificationSpec spec = mMagnificationSpec;
Phil Weaver70439242016-03-10 15:15:49 -0800656 mMagnificationRegion.getBounds(rect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800657 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
658 rect.scale(1.0f / spec.scale);
659 }
660
661 public boolean isMagnifyingLocked() {
662 return mMagnificationSpec.scale > 1.0f;
663 }
664
665 public MagnificationSpec getMagnificationSpecLocked() {
666 return mMagnificationSpec;
667 }
668
669 /** NOTE: This has to be called within a surface transaction. */
670 public void drawWindowIfNeededLocked() {
671 recomputeBoundsLocked();
672 mWindow.drawIfNeeded();
673 }
674
675 public void destroyWindow() {
676 mWindow.releaseSurface();
677 }
678
679 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Robert Carre625fcf2017-09-01 12:36:28 -0700680 final DisplayContent dc = mService.getDefaultDisplayContentLocked();
Robert Carrb1579c82017-09-05 14:54:47 -0700681 mTempLayer = 0;
Wale Ogunwaled1880962016-11-08 10:31:59 -0800682 dc.forAllWindows((w) -> {
683 if (w.isOnScreen() && w.isVisibleLw()
684 && !w.mWinAnimator.mEnterAnimationPending) {
Robert Carrb1579c82017-09-05 14:54:47 -0700685 mTempLayer++;
686 outWindows.put(mTempLayer, w);
Svetoslav8e3feb12014-02-24 13:46:47 -0800687 }
Wale Ogunwaled1880962016-11-08 10:31:59 -0800688 }, false /* traverseTopToBottom */ );
Svetoslav8e3feb12014-02-24 13:46:47 -0800689 }
690
691 private final class ViewportWindow {
692 private static final String SURFACE_TITLE = "Magnification Overlay";
693
Svetoslav8e3feb12014-02-24 13:46:47 -0800694 private final Region mBounds = new Region();
695 private final Rect mDirtyRect = new Rect();
696 private final Paint mPaint = new Paint();
697
Svetoslav8e3feb12014-02-24 13:46:47 -0800698 private final SurfaceControl mSurfaceControl;
699 private final Surface mSurface = new Surface();
700
Svet Ganovb21df802014-09-01 19:06:33 -0700701 private final AnimationController mAnimationController;
702
Svetoslav8e3feb12014-02-24 13:46:47 -0800703 private boolean mShown;
704 private int mAlpha;
705
706 private boolean mInvalidated;
707
708 public ViewportWindow(Context context) {
709 SurfaceControl surfaceControl = null;
710 try {
711 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
Robert Carrb1579c82017-09-05 14:54:47 -0700712 surfaceControl = mService.getDefaultDisplayContentLocked().makeOverlay()
Robert Carre625fcf2017-09-01 12:36:28 -0700713 .setName(SURFACE_TITLE)
714 .setSize(mTempPoint.x, mTempPoint.y) // not a typo
715 .setFormat(PixelFormat.TRANSLUCENT)
716 .build();
Svetoslav8e3feb12014-02-24 13:46:47 -0800717 } catch (OutOfResourcesException oore) {
718 /* ignore */
719 }
720 mSurfaceControl = surfaceControl;
Robert Carre625fcf2017-09-01 12:36:28 -0700721 mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
Phil Weaverd321075e2017-06-13 09:13:35 -0700722 TYPE_MAGNIFICATION_OVERLAY)
Svetoslav8e3feb12014-02-24 13:46:47 -0800723 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
724 mSurfaceControl.setPosition(0, 0);
725 mSurface.copyFrom(mSurfaceControl);
726
Svet Ganovb21df802014-09-01 19:06:33 -0700727 mAnimationController = new AnimationController(context,
Robert Carre625fcf2017-09-01 12:36:28 -0700728 mService.mH.getLooper());
Svet Ganovb21df802014-09-01 19:06:33 -0700729
Svetoslav8e3feb12014-02-24 13:46:47 -0800730 TypedValue typedValue = new TypedValue();
731 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
732 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700733 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800734
735 mPaint.setStyle(Paint.Style.STROKE);
736 mPaint.setStrokeWidth(mBorderWidth);
737 mPaint.setColor(borderColor);
738
Svetoslav8e3feb12014-02-24 13:46:47 -0800739 mInvalidated = true;
740 }
741
742 public void setShown(boolean shown, boolean animate) {
Robert Carre625fcf2017-09-01 12:36:28 -0700743 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800744 if (mShown == shown) {
745 return;
746 }
747 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700748 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800749 if (DEBUG_VIEWPORT_WINDOW) {
750 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
751 }
752 }
753 }
754
755 @SuppressWarnings("unused")
756 // Called reflectively from an animator.
757 public int getAlpha() {
Robert Carre625fcf2017-09-01 12:36:28 -0700758 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800759 return mAlpha;
760 }
761 }
762
763 public void setAlpha(int alpha) {
Robert Carre625fcf2017-09-01 12:36:28 -0700764 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800765 if (mAlpha == alpha) {
766 return;
767 }
768 mAlpha = alpha;
769 invalidate(null);
770 if (DEBUG_VIEWPORT_WINDOW) {
771 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
772 }
773 }
774 }
775
776 public void setBounds(Region bounds) {
Robert Carre625fcf2017-09-01 12:36:28 -0700777 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800778 if (mBounds.equals(bounds)) {
779 return;
780 }
781 mBounds.set(bounds);
782 invalidate(mDirtyRect);
783 if (DEBUG_VIEWPORT_WINDOW) {
784 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
785 }
786 }
787 }
788
789 public void updateSize() {
Robert Carre625fcf2017-09-01 12:36:28 -0700790 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800791 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
792 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
793 invalidate(mDirtyRect);
794 }
795 }
796
797 public void invalidate(Rect dirtyRect) {
798 if (dirtyRect != null) {
799 mDirtyRect.set(dirtyRect);
800 } else {
801 mDirtyRect.setEmpty();
802 }
803 mInvalidated = true;
Robert Carre625fcf2017-09-01 12:36:28 -0700804 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800805 }
806
807 /** NOTE: This has to be called within a surface transaction. */
808 public void drawIfNeeded() {
Robert Carre625fcf2017-09-01 12:36:28 -0700809 synchronized (mService.mWindowMap) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800810 if (!mInvalidated) {
811 return;
812 }
813 mInvalidated = false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800814 if (mAlpha > 0) {
Adrian Roos69364f52018-04-19 18:49:39 +0200815 Canvas canvas = null;
816 try {
817 // Empty dirty rectangle means unspecified.
818 if (mDirtyRect.isEmpty()) {
819 mBounds.getBounds(mDirtyRect);
820 }
821 mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
822 canvas = mSurface.lockCanvas(mDirtyRect);
823 if (DEBUG_VIEWPORT_WINDOW) {
824 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
825 }
826 } catch (IllegalArgumentException iae) {
827 /* ignore */
828 } catch (Surface.OutOfResourcesException oore) {
829 /* ignore */
830 }
831 if (canvas == null) {
832 return;
833 }
834 if (DEBUG_VIEWPORT_WINDOW) {
835 Slog.i(LOG_TAG, "Bounds: " + mBounds);
836 }
837 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
838 mPaint.setAlpha(mAlpha);
839 Path path = mBounds.getBoundaryPath();
840 canvas.drawPath(path, mPaint);
841
842 mSurface.unlockCanvasAndPost(canvas);
Svetoslav8e3feb12014-02-24 13:46:47 -0800843 mSurfaceControl.show();
844 } else {
845 mSurfaceControl.hide();
846 }
847 }
848 }
849
850 public void releaseSurface() {
851 mSurfaceControl.release();
852 mSurface.release();
853 }
Svet Ganovb21df802014-09-01 19:06:33 -0700854
855 private final class AnimationController extends Handler {
856 private static final String PROPERTY_NAME_ALPHA = "alpha";
857
858 private static final int MIN_ALPHA = 0;
859 private static final int MAX_ALPHA = 255;
860
861 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
862
863 private final ValueAnimator mShowHideFrameAnimator;
864
865 public AnimationController(Context context, Looper looper) {
866 super(looper);
867 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
868 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
869
870 Interpolator interpolator = new DecelerateInterpolator(2.5f);
871 final long longAnimationDuration = context.getResources().getInteger(
872 com.android.internal.R.integer.config_longAnimTime);
873
874 mShowHideFrameAnimator.setInterpolator(interpolator);
875 mShowHideFrameAnimator.setDuration(longAnimationDuration);
876 }
877
878 public void onFrameShownStateChanged(boolean shown, boolean animate) {
879 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
880 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
881 }
882
883 @Override
884 public void handleMessage(Message message) {
885 switch (message.what) {
886 case MSG_FRAME_SHOWN_STATE_CHANGED: {
887 final boolean shown = message.arg1 == 1;
888 final boolean animate = message.arg2 == 1;
889
890 if (animate) {
891 if (mShowHideFrameAnimator.isRunning()) {
892 mShowHideFrameAnimator.reverse();
893 } else {
894 if (shown) {
895 mShowHideFrameAnimator.start();
896 } else {
897 mShowHideFrameAnimator.reverse();
898 }
899 }
900 } else {
901 mShowHideFrameAnimator.cancel();
902 if (shown) {
903 setAlpha(MAX_ALPHA);
904 } else {
905 setAlpha(MIN_ALPHA);
906 }
907 }
908 } break;
909 }
910 }
911 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800912 }
913 }
914
915 private class MyHandler extends Handler {
Phil Weaver70439242016-03-10 15:15:49 -0800916 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -0800917 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
918 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
919 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
920 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
921
922 public MyHandler(Looper looper) {
923 super(looper);
924 }
925
926 @Override
927 public void handleMessage(Message message) {
928 switch (message.what) {
Phil Weaver70439242016-03-10 15:15:49 -0800929 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500930 final SomeArgs args = (SomeArgs) message.obj;
931 final Region magnifiedBounds = (Region) args.arg1;
Phil Weaver70439242016-03-10 15:15:49 -0800932 mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500933 magnifiedBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800934 } break;
935
936 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
937 SomeArgs args = (SomeArgs) message.obj;
938 final int left = args.argi1;
939 final int top = args.argi2;
940 final int right = args.argi3;
941 final int bottom = args.argi4;
942 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
943 args.recycle();
944 } break;
945
946 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
947 mCallbacks.onUserContextChanged();
948 } break;
949
950 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
951 final int rotation = message.arg1;
952 mCallbacks.onRotationChanged(rotation);
953 } break;
954
955 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
Robert Carre625fcf2017-09-01 12:36:28 -0700956 synchronized (mService.mWindowMap) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800957 if (mMagnifedViewport.isMagnifyingLocked()
958 || isForceShowingMagnifiableBoundsLocked()) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800959 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
Robert Carre625fcf2017-09-01 12:36:28 -0700960 mService.scheduleAnimationLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800961 }
962 }
963 } break;
964 }
965 }
966 }
967 }
968
969 /**
970 * This class encapsulates the functionality related to computing the windows
971 * reported for accessibility purposes. These windows are all windows a sighted
972 * user can see on the screen.
973 */
974 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800975 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
976 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800977
978 private static final boolean DEBUG = false;
979
980 private final SparseArray<WindowState> mTempWindowStates =
981 new SparseArray<WindowState>();
982
983 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
984
985 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
986
987 private final RectF mTempRectF = new RectF();
988
989 private final Matrix mTempMatrix = new Matrix();
990
991 private final Point mTempPoint = new Point();
992
993 private final Rect mTempRect = new Rect();
994
995 private final Region mTempRegion = new Region();
996
997 private final Region mTempRegion1 = new Region();
998
999 private final Context mContext;
1000
Robert Carre625fcf2017-09-01 12:36:28 -07001001 private final WindowManagerService mService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001002
1003 private final Handler mHandler;
1004
1005 private final WindowsForAccessibilityCallback mCallback;
1006
Svetoslavf7174e82014-06-12 11:29:35 -07001007 private final long mRecurringAccessibilityEventsIntervalMillis;
1008
Robert Carrb1579c82017-09-05 14:54:47 -07001009 private int mTempLayer = 0;
1010
Svetoslav8e3feb12014-02-24 13:46:47 -08001011 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
1012 WindowsForAccessibilityCallback callback) {
1013 mContext = windowManagerService.mContext;
Robert Carre625fcf2017-09-01 12:36:28 -07001014 mService = windowManagerService;
Svetoslav8e3feb12014-02-24 13:46:47 -08001015 mCallback = callback;
Robert Carre625fcf2017-09-01 12:36:28 -07001016 mHandler = new MyHandler(mService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -07001017 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1018 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -08001019 computeChangedWindows();
1020 }
1021
Svetoslav3a0d8782014-12-04 12:50:11 -08001022 public void performComputeChangedWindowsNotLocked() {
1023 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
1024 computeChangedWindows();
1025 }
1026
Svetoslavf7174e82014-06-12 11:29:35 -07001027 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -08001028 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001029 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1030 mRecurringAccessibilityEventsIntervalMillis);
1031 }
1032 }
1033
Svetoslav8e3feb12014-02-24 13:46:47 -08001034 public void computeChangedWindows() {
1035 if (DEBUG) {
1036 Slog.i(LOG_TAG, "computeChangedWindows()");
1037 }
1038
Svetoslav3a0d8782014-12-04 12:50:11 -08001039 boolean windowsChanged = false;
1040 List<WindowInfo> windows = new ArrayList<WindowInfo>();
1041
Robert Carre625fcf2017-09-01 12:36:28 -07001042 synchronized (mService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -07001043 // Do not send the windows if there is no current focus as
1044 // the window manager is still looking for where to put it.
1045 // We will do the work when we get a focus change callback.
Robert Carre625fcf2017-09-01 12:36:28 -07001046 if (mService.mCurrentFocus == null) {
Svetoslavf7174e82014-06-12 11:29:35 -07001047 return;
1048 }
1049
Svetoslav8e3feb12014-02-24 13:46:47 -08001050 WindowManager windowManager = (WindowManager)
1051 mContext.getSystemService(Context.WINDOW_SERVICE);
1052 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1053 final int screenWidth = mTempPoint.x;
1054 final int screenHeight = mTempPoint.y;
1055
1056 Region unaccountedSpace = mTempRegion;
1057 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1058
Wale Ogunwalef7cab102016-10-25 15:25:14 -07001059 final SparseArray<WindowState> visibleWindows = mTempWindowStates;
Svetoslav8e3feb12014-02-24 13:46:47 -08001060 populateVisibleWindowsOnScreenLocked(visibleWindows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001061 Set<IBinder> addedWindows = mTempBinderSet;
1062 addedWindows.clear();
1063
Svetoslavf7174e82014-06-12 11:29:35 -07001064 boolean focusedWindowAdded = false;
1065
Svetoslav8e3feb12014-02-24 13:46:47 -08001066 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001067 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001068 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001069 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001070 final int flags = windowState.mAttrs.flags;
Allen Hairf20ac2c2016-02-11 17:42:59 -08001071 final Task task = windowState.getTask();
1072
1073 // If the window is part of a task that we're finished with - ignore.
1074 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1075 continue;
1076 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001077
Phil Weaverb2779532017-12-18 17:09:32 -08001078 // Ignore non-touchable windows, except the split-screen divider, which is
1079 // occasionally non-touchable but still useful for identifying split-screen
1080 // mode.
1081 if (((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
1082 && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001083 continue;
1084 }
1085
Alan Viverette9538eea2014-11-13 14:49:20 -08001086 // Compute the bounds in the screen.
1087 final Rect boundsInScreen = mTempRect;
1088 computeWindowBoundsInScreen(windowState, boundsInScreen);
1089
Svetoslav8e3feb12014-02-24 13:46:47 -08001090 // If the window is completely covered by other windows - ignore.
1091 if (unaccountedSpace.quickReject(boundsInScreen)) {
1092 continue;
1093 }
1094
1095 // Add windows of certain types not covered by modal windows.
1096 if (isReportedWindowType(windowState.mAttrs.type)) {
1097 // Add the window to the ones to be reported.
Eugene Susla18e7fc112018-03-16 14:35:31 -07001098 addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
Svetoslavf7174e82014-06-12 11:29:35 -07001099 if (windowState.isFocused()) {
1100 focusedWindowAdded = true;
1101 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001102 }
1103
Alan Viveretted0c73f42014-11-18 10:25:04 -08001104 if (windowState.mAttrs.type !=
1105 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
Eugene Suslabe9106a2018-03-30 11:56:16 -07001106
1107 // Account for the space this window takes if the window
1108 // is not an accessibility overlay which does not change
1109 // the reported windows.
Alan Viveretted0c73f42014-11-18 10:25:04 -08001110 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1111 Region.Op.REVERSE_DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -08001112
Eugene Suslabe9106a2018-03-30 11:56:16 -07001113 // If a window is modal it prevents other windows from being touched
1114 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1115 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
1116 // Account for all space in the task, whether the windows in it are
1117 // touchable or not. The modal window blocks all touches from the task's
1118 // area.
1119 unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
1120 Region.Op.REVERSE_DIFFERENCE);
Phil Weaverac9ad702016-07-27 18:03:10 -07001121
Eugene Suslabe9106a2018-03-30 11:56:16 -07001122 if (task != null) {
1123 // If the window is associated with a particular task, we can skip the
1124 // rest of the windows for that task.
1125 skipRemainingWindowsForTasks.add(task.mTaskId);
1126 continue;
1127 } else {
1128 // If the window is not associated with a particular task, then it is
1129 // globally modal. In this case we can skip all remaining windows.
1130 break;
1131 }
Allen Hairf20ac2c2016-02-11 17:42:59 -08001132 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001133 }
Eugene Suslabe9106a2018-03-30 11:56:16 -07001134
Phil Weaverac9ad702016-07-27 18:03:10 -07001135 // We figured out what is touchable for the entire screen - done.
1136 if (unaccountedSpace.isEmpty()) {
1137 break;
1138 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001139 }
1140
Svetoslavf7174e82014-06-12 11:29:35 -07001141 // Always report the focused window.
1142 if (!focusedWindowAdded) {
1143 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1144 WindowState windowState = visibleWindows.valueAt(i);
1145 if (windowState.isFocused()) {
1146 // Compute the bounds in the screen.
1147 Rect boundsInScreen = mTempRect;
1148 computeWindowBoundsInScreen(windowState, boundsInScreen);
1149
1150 // Add the window to the ones to be reported.
Eugene Susla18e7fc112018-03-16 14:35:31 -07001151 addPopulatedWindowInfo(
1152 windowState, boundsInScreen, windows, addedWindows);
Svetoslavf7174e82014-06-12 11:29:35 -07001153 break;
1154 }
1155 }
1156 }
1157
Svetoslav8e3feb12014-02-24 13:46:47 -08001158 // Remove child/parent references to windows that were not added.
1159 final int windowCount = windows.size();
1160 for (int i = 0; i < windowCount; i++) {
1161 WindowInfo window = windows.get(i);
1162 if (!addedWindows.contains(window.parentToken)) {
1163 window.parentToken = null;
1164 }
1165 if (window.childTokens != null) {
1166 final int childTokenCount = window.childTokens.size();
1167 for (int j = childTokenCount - 1; j >= 0; j--) {
1168 if (!addedWindows.contains(window.childTokens.get(j))) {
1169 window.childTokens.remove(j);
1170 }
1171 }
1172 // Leave the child token list if empty.
1173 }
1174 }
1175
1176 visibleWindows.clear();
1177 addedWindows.clear();
1178
1179 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001180 if (mOldWindows.size() != windows.size()) {
1181 // Different size means something changed.
1182 windowsChanged = true;
1183 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1184 // Since we always traverse windows from high to low layer
1185 // the old and new windows at the same index should be the
1186 // same, otherwise something changed.
1187 for (int i = 0; i < windowCount; i++) {
1188 WindowInfo oldWindow = mOldWindows.get(i);
1189 WindowInfo newWindow = windows.get(i);
1190 // We do not care for layer changes given the window
1191 // order does not change. This brings no new information
1192 // to the clients.
1193 if (windowChangedNoLayer(oldWindow, newWindow)) {
1194 windowsChanged = true;
1195 break;
1196 }
1197 }
1198 }
1199
1200 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001201 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001202 }
1203 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001204
1205 // Now we do not hold the lock, so send the windows over.
1206 if (windowsChanged) {
1207 if (DEBUG) {
1208 Log.i(LOG_TAG, "Windows changed:" + windows);
1209 }
1210 mCallback.onWindowsForAccessibilityChanged(windows);
1211 } else {
1212 if (DEBUG) {
1213 Log.i(LOG_TAG, "No windows changed.");
1214 }
1215 }
1216
1217 // Recycle the windows as we do not need them.
1218 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001219 }
1220
Svetoslavf7174e82014-06-12 11:29:35 -07001221 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1222 // Get the touchable frame.
1223 Region touchableRegion = mTempRegion1;
1224 windowState.getTouchableRegion(touchableRegion);
1225 Rect touchableFrame = mTempRect;
1226 touchableRegion.getBounds(touchableFrame);
1227
1228 // Move to origin as all transforms are captured by the matrix.
1229 RectF windowFrame = mTempRectF;
1230 windowFrame.set(touchableFrame);
1231 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1232
1233 // Map the frame to get what appears on the screen.
1234 Matrix matrix = mTempMatrix;
1235 populateTransformationMatrixLocked(windowState, matrix);
1236 matrix.mapRect(windowFrame);
1237
1238 // Got the bounds.
1239 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1240 (int) windowFrame.right, (int) windowFrame.bottom);
1241 }
1242
Eugene Susla18e7fc112018-03-16 14:35:31 -07001243 private static void addPopulatedWindowInfo(
1244 WindowState windowState, Rect boundsInScreen,
1245 List<WindowInfo> out, Set<IBinder> tokenOut) {
Wale Ogunwaleadde52e2016-07-16 13:11:55 -07001246 final WindowInfo window = windowState.getWindowInfo();
Svetoslavf7174e82014-06-12 11:29:35 -07001247 window.boundsInScreen.set(boundsInScreen);
Eugene Susla18e7fc112018-03-16 14:35:31 -07001248 window.layer = tokenOut.size();
1249 out.add(window);
1250 tokenOut.add(window.token);
Svetoslavf7174e82014-06-12 11:29:35 -07001251 }
1252
Svetoslav8e3feb12014-02-24 13:46:47 -08001253 private void cacheWindows(List<WindowInfo> windows) {
1254 final int oldWindowCount = mOldWindows.size();
1255 for (int i = oldWindowCount - 1; i >= 0; i--) {
1256 mOldWindows.remove(i).recycle();
1257 }
1258 final int newWindowCount = windows.size();
1259 for (int i = 0; i < newWindowCount; i++) {
1260 WindowInfo newWindow = windows.get(i);
1261 mOldWindows.add(WindowInfo.obtain(newWindow));
1262 }
1263 }
1264
1265 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1266 if (oldWindow == newWindow) {
1267 return false;
1268 }
Svetoslavf7174e82014-06-12 11:29:35 -07001269 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001270 return true;
1271 }
Svetoslavf7174e82014-06-12 11:29:35 -07001272 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001273 return true;
1274 }
1275 if (oldWindow.type != newWindow.type) {
1276 return true;
1277 }
1278 if (oldWindow.focused != newWindow.focused) {
1279 return true;
1280 }
1281 if (oldWindow.token == null) {
1282 if (newWindow.token != null) {
1283 return true;
1284 }
1285 } else if (!oldWindow.token.equals(newWindow.token)) {
1286 return true;
1287 }
1288 if (oldWindow.parentToken == null) {
1289 if (newWindow.parentToken != null) {
1290 return true;
1291 }
1292 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1293 return true;
1294 }
1295 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1296 return true;
1297 }
1298 if (oldWindow.childTokens != null && newWindow.childTokens != null
1299 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1300 return true;
1301 }
Phil Weaver396d5492016-03-22 17:53:50 -07001302 if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
1303 return true;
1304 }
1305 if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
1306 return true;
1307 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001308 return false;
1309 }
1310
Svetoslav3a0d8782014-12-04 12:50:11 -08001311 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001312 final int windowCount = windows.size();
1313 for (int i = windowCount - 1; i >= 0; i--) {
1314 windows.remove(i).recycle();
1315 }
1316 }
1317
1318 private static boolean isReportedWindowType(int windowType) {
Jorim Jaggi73294b62016-10-26 18:02:36 -07001319 return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
Svetoslav8e3feb12014-02-24 13:46:47 -08001320 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1321 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1322 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001323 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001324 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Phil Weaverd321075e2017-06-13 09:13:35 -07001325 && windowType != TYPE_MAGNIFICATION_OVERLAY
Svetoslav8e3feb12014-02-24 13:46:47 -08001326 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1327 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1328 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1329 }
1330
1331 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
Robert Carre625fcf2017-09-01 12:36:28 -07001332 final DisplayContent dc = mService.getDefaultDisplayContentLocked();
Robert Carrb1579c82017-09-05 14:54:47 -07001333 mTempLayer = 0;
Wale Ogunwaled1880962016-11-08 10:31:59 -08001334 dc.forAllWindows((w) -> {
1335 if (w.isVisibleLw()) {
Robert Carrb1579c82017-09-05 14:54:47 -07001336 outWindows.put(mTempLayer++, w);
Svetoslav8e3feb12014-02-24 13:46:47 -08001337 }
Wale Ogunwaled1880962016-11-08 10:31:59 -08001338 }, false /* traverseTopToBottom */ );
Svetoslav8e3feb12014-02-24 13:46:47 -08001339 }
1340
1341 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001342 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001343
1344 public MyHandler(Looper looper) {
1345 super(looper, null, false);
1346 }
1347
1348 @Override
1349 @SuppressWarnings("unchecked")
1350 public void handleMessage(Message message) {
1351 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001352 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1353 computeChangedWindows();
1354 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001355 }
1356 }
1357 }
1358 }
1359}