blob: 2c158188edbc4857a31996f7b78a47259412d6e9 [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
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080019import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
21
Svetoslav8e3feb12014-02-24 13:46:47 -080022import android.animation.ObjectAnimator;
23import android.animation.ValueAnimator;
24import android.app.Service;
25import android.content.Context;
26import android.graphics.Canvas;
27import android.graphics.Color;
28import android.graphics.Matrix;
29import android.graphics.Paint;
30import android.graphics.Path;
31import android.graphics.PixelFormat;
32import android.graphics.Point;
33import android.graphics.PorterDuff.Mode;
34import android.graphics.Rect;
35import android.graphics.RectF;
36import android.graphics.Region;
37import android.os.Handler;
38import android.os.IBinder;
39import android.os.Looper;
40import android.os.Message;
41import android.util.ArraySet;
42import android.util.Log;
43import android.util.Slog;
44import android.util.SparseArray;
45import android.util.TypedValue;
46import android.view.MagnificationSpec;
47import android.view.Surface;
48import android.view.Surface.OutOfResourcesException;
49import android.view.SurfaceControl;
Svetoslavf7174e82014-06-12 11:29:35 -070050import android.view.ViewConfiguration;
Svetoslav8e3feb12014-02-24 13:46:47 -080051import android.view.WindowInfo;
52import android.view.WindowManager;
53import android.view.WindowManagerInternal.MagnificationCallbacks;
54import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
55import android.view.WindowManagerPolicy;
56import android.view.animation.DecelerateInterpolator;
57import android.view.animation.Interpolator;
58
59import com.android.internal.R;
60import com.android.internal.os.SomeArgs;
61
62import java.util.ArrayList;
Allen Hairf20ac2c2016-02-11 17:42:59 -080063import java.util.HashSet;
Svetoslav8e3feb12014-02-24 13:46:47 -080064import java.util.List;
65import java.util.Set;
66
67/**
68 * This class contains the accessibility related logic of the window manger.
69 */
70final class AccessibilityController {
71
72 private final WindowManagerService mWindowManagerService;
73
74 private static final float[] sTempFloats = new float[9];
75
76 public AccessibilityController(WindowManagerService service) {
77 mWindowManagerService = service;
78 }
79
80 private DisplayMagnifier mDisplayMagnifier;
81
82 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
83
84 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
85 if (callbacks != null) {
86 if (mDisplayMagnifier != null) {
87 throw new IllegalStateException("Magnification callbacks already set!");
88 }
89 mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
90 } else {
91 if (mDisplayMagnifier == null) {
92 throw new IllegalStateException("Magnification callbacks already cleared!");
93 }
94 mDisplayMagnifier.destroyLocked();
95 mDisplayMagnifier = null;
96 }
97 }
98
99 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
100 if (callback != null) {
101 if (mWindowsForAccessibilityObserver != null) {
102 throw new IllegalStateException(
103 "Windows for accessibility callback already set!");
104 }
105 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
106 mWindowManagerService, callback);
107 } else {
108 if (mWindowsForAccessibilityObserver == null) {
109 throw new IllegalStateException(
110 "Windows for accessibility callback already cleared!");
111 }
112 mWindowsForAccessibilityObserver = null;
113 }
114 }
115
116 public void setMagnificationSpecLocked(MagnificationSpec spec) {
117 if (mDisplayMagnifier != null) {
118 mDisplayMagnifier.setMagnificationSpecLocked(spec);
119 }
120 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700121 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800122 }
123 }
124
Svetoslavf7174e82014-06-12 11:29:35 -0700125 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800126 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700127 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800128 }
129 // Not relevant for the window observer.
130 }
131
132 public void onWindowLayersChangedLocked() {
133 if (mDisplayMagnifier != null) {
134 mDisplayMagnifier.onWindowLayersChangedLocked();
135 }
136 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700137 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800138 }
139 }
140
141 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
142 if (mDisplayMagnifier != null) {
143 mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
144 }
145 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700146 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800147 }
148 }
149
150 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
151 if (mDisplayMagnifier != null) {
152 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
153 }
154 // Not relevant for the window observer.
155 }
156
157 public void onWindowTransitionLocked(WindowState windowState, int transition) {
158 if (mDisplayMagnifier != null) {
159 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
160 }
161 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700162 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800163 }
164 }
165
Svetoslav3a0d8782014-12-04 12:50:11 -0800166 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800167 // Not relevant for the display magnifier.
168
Svetoslav3a0d8782014-12-04 12:50:11 -0800169 WindowsForAccessibilityObserver observer = null;
170 synchronized (mWindowManagerService) {
171 observer = mWindowsForAccessibilityObserver;
172 }
173 if (observer != null) {
174 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800175 }
176 }
177
Svetoslav4604abc2014-06-10 18:59:30 -0700178
Svetoslavf7174e82014-06-12 11:29:35 -0700179 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700180 // Not relevant for the display magnifier.
181
182 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700183 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700184 }
185 }
186
Svetoslav8e3feb12014-02-24 13:46:47 -0800187 /** NOTE: This has to be called within a surface transaction. */
188 public void drawMagnifiedRegionBorderIfNeededLocked() {
189 if (mDisplayMagnifier != null) {
190 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
191 }
192 // Not relevant for the window observer.
193 }
194
195 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
196 if (mDisplayMagnifier != null) {
197 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
198 }
199 return null;
200 }
201
202 public boolean hasCallbacksLocked() {
203 return (mDisplayMagnifier != null
204 || mWindowsForAccessibilityObserver != null);
205 }
206
207 private static void populateTransformationMatrixLocked(WindowState windowState,
208 Matrix outMatrix) {
209 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
210 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
211 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
212 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
Filip Gruszczynski2a6a2c22015-10-14 12:00:53 -0700213 sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
214 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
Svetoslav8e3feb12014-02-24 13:46:47 -0800215 sTempFloats[Matrix.MPERSP_0] = 0;
216 sTempFloats[Matrix.MPERSP_1] = 0;
217 sTempFloats[Matrix.MPERSP_2] = 1;
218 outMatrix.setValues(sTempFloats);
219 }
220
221 /**
222 * This class encapsulates the functionality related to display magnification.
223 */
224 private static final class DisplayMagnifier {
225
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800226 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800227
228 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
229 private static final boolean DEBUG_ROTATION = false;
230 private static final boolean DEBUG_LAYERS = false;
231 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
232 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
233
234 private final Rect mTempRect1 = new Rect();
235 private final Rect mTempRect2 = new Rect();
236
237 private final Region mTempRegion1 = new Region();
238 private final Region mTempRegion2 = new Region();
239 private final Region mTempRegion3 = new Region();
240 private final Region mTempRegion4 = new Region();
241
242 private final Context mContext;
243 private final WindowManagerService mWindowManagerService;
244 private final MagnifiedViewport mMagnifedViewport;
245 private final Handler mHandler;
246
247 private final MagnificationCallbacks mCallbacks;
248
249 private final long mLongAnimationDuration;
250
251 public DisplayMagnifier(WindowManagerService windowManagerService,
252 MagnificationCallbacks callbacks) {
253 mContext = windowManagerService.mContext;
254 mWindowManagerService = windowManagerService;
255 mCallbacks = callbacks;
256 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
257 mMagnifedViewport = new MagnifiedViewport();
258 mLongAnimationDuration = mContext.getResources().getInteger(
259 com.android.internal.R.integer.config_longAnimTime);
260 }
261
262 public void setMagnificationSpecLocked(MagnificationSpec spec) {
263 mMagnifedViewport.updateMagnificationSpecLocked(spec);
264 mMagnifedViewport.recomputeBoundsLocked();
265 mWindowManagerService.scheduleAnimationLocked();
266 }
267
Svetoslavf7174e82014-06-12 11:29:35 -0700268 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800269 if (DEBUG_RECTANGLE_REQUESTED) {
270 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
271 }
272 if (!mMagnifedViewport.isMagnifyingLocked()) {
273 return;
274 }
275 Rect magnifiedRegionBounds = mTempRect2;
276 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
277 if (magnifiedRegionBounds.contains(rectangle)) {
278 return;
279 }
280 SomeArgs args = SomeArgs.obtain();
281 args.argi1 = rectangle.left;
282 args.argi2 = rectangle.top;
283 args.argi3 = rectangle.right;
284 args.argi4 = rectangle.bottom;
285 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
286 args).sendToTarget();
287 }
288
289 public void onWindowLayersChangedLocked() {
290 if (DEBUG_LAYERS) {
291 Slog.i(LOG_TAG, "Layers changed.");
292 }
293 mMagnifedViewport.recomputeBoundsLocked();
294 mWindowManagerService.scheduleAnimationLocked();
295 }
296
297 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
298 if (DEBUG_ROTATION) {
299 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
300 + " displayId: " + displayContent.getDisplayId());
301 }
302 mMagnifedViewport.onRotationChangedLocked();
303 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
304 }
305
306 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
307 if (DEBUG_WINDOW_TRANSITIONS) {
308 Slog.i(LOG_TAG, "Window transition: "
309 + AppTransition.appTransitionToString(transition)
310 + " displayId: " + windowState.getDisplayId());
311 }
312 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
313 if (magnifying) {
314 switch (transition) {
315 case AppTransition.TRANSIT_ACTIVITY_OPEN:
316 case AppTransition.TRANSIT_TASK_OPEN:
317 case AppTransition.TRANSIT_TASK_TO_FRONT:
318 case AppTransition.TRANSIT_WALLPAPER_OPEN:
319 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
320 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
321 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
322 }
323 }
324 }
325 }
326
327 public void onWindowTransitionLocked(WindowState windowState, int transition) {
328 if (DEBUG_WINDOW_TRANSITIONS) {
329 Slog.i(LOG_TAG, "Window transition: "
330 + AppTransition.appTransitionToString(transition)
331 + " displayId: " + windowState.getDisplayId());
332 }
333 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
334 final int type = windowState.mAttrs.type;
335 switch (transition) {
336 case WindowManagerPolicy.TRANSIT_ENTER:
337 case WindowManagerPolicy.TRANSIT_SHOW: {
338 if (!magnifying) {
339 break;
340 }
341 switch (type) {
342 case WindowManager.LayoutParams.TYPE_APPLICATION:
343 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
344 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
345 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700346 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800347 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
348 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
349 case WindowManager.LayoutParams.TYPE_PHONE:
350 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
351 case WindowManager.LayoutParams.TYPE_TOAST:
352 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
353 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
354 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
355 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
356 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
357 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500358 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200359 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800360 Rect magnifiedRegionBounds = mTempRect2;
361 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
362 magnifiedRegionBounds);
363 Rect touchableRegionBounds = mTempRect1;
364 windowState.getTouchableRegion(mTempRegion1);
365 mTempRegion1.getBounds(touchableRegionBounds);
366 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
367 mCallbacks.onRectangleOnScreenRequested(
368 touchableRegionBounds.left,
369 touchableRegionBounds.top,
370 touchableRegionBounds.right,
371 touchableRegionBounds.bottom);
372 }
373 } break;
374 } break;
375 }
376 }
377 }
378
379 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
380 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
381 if (spec != null && !spec.isNop()) {
382 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
383 final int windowType = windowState.mAttrs.type;
384 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
385 && !policy.canMagnifyWindow(windowType)) {
386 return null;
387 }
388 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
389 return null;
390 }
391 }
392 return spec;
393 }
394
395 public void destroyLocked() {
396 mMagnifedViewport.destroyWindow();
397 }
398
399 /** NOTE: This has to be called within a surface transaction. */
400 public void drawMagnifiedRegionBorderIfNeededLocked() {
401 mMagnifedViewport.drawWindowIfNeededLocked();
402 }
403
404 private final class MagnifiedViewport {
405
Svetoslav8e3feb12014-02-24 13:46:47 -0800406 private final SparseArray<WindowState> mTempWindowStates =
407 new SparseArray<WindowState>();
408
409 private final RectF mTempRectF = new RectF();
410
411 private final Point mTempPoint = new Point();
412
413 private final Matrix mTempMatrix = new Matrix();
414
415 private final Region mMagnifiedBounds = new Region();
416 private final Region mOldMagnifiedBounds = new Region();
Alan Viverette214fb682015-11-17 09:47:11 -0500417 private final Region mOldAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800418
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800419 private final Path mCircularPath;
420
Svetoslav8e3feb12014-02-24 13:46:47 -0800421 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
422
423 private final WindowManager mWindowManager;
424
Svetoslav7505e332014-08-22 12:14:28 -0700425 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800426 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700427 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800428
429 private final ViewportWindow mWindow;
430
431 private boolean mFullRedrawNeeded;
432
433 public MagnifiedViewport() {
434 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800435 mBorderWidth = mContext.getResources().getDimension(
436 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700437 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
438 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800439 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800440
Adam Powell01f280d2015-05-18 16:07:42 -0700441 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800442 mCircularPath = new Path();
443 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
444 final int centerXY = mTempPoint.x / 2;
445 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
446 } else {
447 mCircularPath = null;
448 }
449
Svetoslav8e3feb12014-02-24 13:46:47 -0800450 recomputeBoundsLocked();
451 }
452
453 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
454 if (spec != null) {
455 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
456 } else {
457 mMagnificationSpec.clear();
458 }
459 // If this message is pending we are in a rotation animation and do not want
460 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700461 if (!mHandler.hasMessages(
462 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800463 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
464 }
465 }
466
467 public void recomputeBoundsLocked() {
468 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
469 final int screenWidth = mTempPoint.x;
470 final int screenHeight = mTempPoint.y;
471
472 Region magnifiedBounds = mMagnifiedBounds;
473 magnifiedBounds.set(0, 0, 0, 0);
474
475 Region availableBounds = mTempRegion1;
476 availableBounds.set(0, 0, screenWidth, screenHeight);
477
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800478 if (mCircularPath != null) {
479 availableBounds.setPath(mCircularPath, availableBounds);
480 }
481
Svetoslav8e3feb12014-02-24 13:46:47 -0800482 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700483 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800484
485 SparseArray<WindowState> visibleWindows = mTempWindowStates;
486 visibleWindows.clear();
487 populateWindowsOnScreenLocked(visibleWindows);
488
489 final int visibleWindowCount = visibleWindows.size();
490 for (int i = visibleWindowCount - 1; i >= 0; i--) {
491 WindowState windowState = visibleWindows.valueAt(i);
492 if (windowState.mAttrs.type == WindowManager
493 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
494 continue;
495 }
496
497 Region windowBounds = mTempRegion2;
498 Matrix matrix = mTempMatrix;
499 populateTransformationMatrixLocked(windowState, matrix);
500 RectF windowFrame = mTempRectF;
501
502 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
503 windowFrame.set(windowState.mFrame);
504 windowFrame.offset(-windowFrame.left, -windowFrame.top);
505 matrix.mapRect(windowFrame);
506 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
507 (int) windowFrame.right, (int) windowFrame.bottom);
508 magnifiedBounds.op(windowBounds, Region.Op.UNION);
509 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
510 } else {
511 Region touchableRegion = mTempRegion3;
512 windowState.getTouchableRegion(touchableRegion);
513 Rect touchableFrame = mTempRect1;
514 touchableRegion.getBounds(touchableFrame);
515 windowFrame.set(touchableFrame);
516 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
517 matrix.mapRect(windowFrame);
518 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
519 (int) windowFrame.right, (int) windowFrame.bottom);
520 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
521 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
522 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
523 }
524
525 Region accountedBounds = mTempRegion2;
526 accountedBounds.set(magnifiedBounds);
527 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
528 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
529
530 if (accountedBounds.isRect()) {
531 Rect accountedFrame = mTempRect1;
532 accountedBounds.getBounds(accountedFrame);
533 if (accountedFrame.width() == screenWidth
534 && accountedFrame.height() == screenHeight) {
535 break;
536 }
537 }
538 }
539
540 visibleWindows.clear();
541
Svetoslav7505e332014-08-22 12:14:28 -0700542 magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
543 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800544 Region.Op.INTERSECT);
545
Alan Viverette214fb682015-11-17 09:47:11 -0500546 final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(magnifiedBounds);
547 final boolean availableChanged = !mOldAvailableBounds.equals(availableBounds);
548 if (magnifiedChanged || availableChanged) {
549 if (magnifiedChanged) {
550 mWindow.setBounds(magnifiedBounds);
551 Rect dirtyRect = mTempRect1;
552 if (mFullRedrawNeeded) {
553 mFullRedrawNeeded = false;
554 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
555 screenWidth - mDrawBorderInset,
556 screenHeight - mDrawBorderInset);
557 mWindow.invalidate(dirtyRect);
558 } else {
559 Region dirtyRegion = mTempRegion3;
560 dirtyRegion.set(magnifiedBounds);
561 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
562 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
563 dirtyRegion.getBounds(dirtyRect);
564 mWindow.invalidate(dirtyRect);
565 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800566
Alan Viverette214fb682015-11-17 09:47:11 -0500567 mOldMagnifiedBounds.set(magnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800568 }
569
Alan Viverette214fb682015-11-17 09:47:11 -0500570 if (availableChanged) {
571 mOldAvailableBounds.set(availableBounds);
572 }
573
574 final SomeArgs args = SomeArgs.obtain();
575 args.arg1 = Region.obtain(magnifiedBounds);
576 args.arg2 = Region.obtain(availableBounds);
577 mHandler.obtainMessage(
578 MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800579 }
580 }
581
582 public void onRotationChangedLocked() {
583 // If we are magnifying, hide the magnified border window immediately so
584 // the user does not see strange artifacts during rotation. The screenshot
585 // used for rotation has already the border. After the rotation is complete
586 // we will show the border.
587 if (isMagnifyingLocked()) {
588 setMagnifiedRegionBorderShownLocked(false, false);
589 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700590 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800591 Message message = mHandler.obtainMessage(
592 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
593 mHandler.sendMessageDelayed(message, delay);
594 }
595 recomputeBoundsLocked();
596 mWindow.updateSize();
597 }
598
599 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
600 if (shown) {
601 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700602 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800603 }
604 mWindow.setShown(shown, animate);
605 }
606
607 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
608 MagnificationSpec spec = mMagnificationSpec;
609 mMagnifiedBounds.getBounds(rect);
610 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
611 rect.scale(1.0f / spec.scale);
612 }
613
614 public boolean isMagnifyingLocked() {
615 return mMagnificationSpec.scale > 1.0f;
616 }
617
618 public MagnificationSpec getMagnificationSpecLocked() {
619 return mMagnificationSpec;
620 }
621
622 /** NOTE: This has to be called within a surface transaction. */
623 public void drawWindowIfNeededLocked() {
624 recomputeBoundsLocked();
625 mWindow.drawIfNeeded();
626 }
627
628 public void destroyWindow() {
629 mWindow.releaseSurface();
630 }
631
632 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
633 DisplayContent displayContent = mWindowManagerService
634 .getDefaultDisplayContentLocked();
635 WindowList windowList = displayContent.getWindowList();
636 final int windowCount = windowList.size();
637 for (int i = 0; i < windowCount; i++) {
638 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800639 if (windowState.isOnScreen() &&
640 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800641 outWindows.put(windowState.mLayer, windowState);
642 }
643 }
644 }
645
646 private final class ViewportWindow {
647 private static final String SURFACE_TITLE = "Magnification Overlay";
648
Svetoslav8e3feb12014-02-24 13:46:47 -0800649 private final Region mBounds = new Region();
650 private final Rect mDirtyRect = new Rect();
651 private final Paint mPaint = new Paint();
652
Svetoslav8e3feb12014-02-24 13:46:47 -0800653 private final SurfaceControl mSurfaceControl;
654 private final Surface mSurface = new Surface();
655
Svet Ganovb21df802014-09-01 19:06:33 -0700656 private final AnimationController mAnimationController;
657
Svetoslav8e3feb12014-02-24 13:46:47 -0800658 private boolean mShown;
659 private int mAlpha;
660
661 private boolean mInvalidated;
662
663 public ViewportWindow(Context context) {
664 SurfaceControl surfaceControl = null;
665 try {
666 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
667 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
668 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
669 SurfaceControl.HIDDEN);
670 } catch (OutOfResourcesException oore) {
671 /* ignore */
672 }
673 mSurfaceControl = surfaceControl;
674 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
675 .getLayerStack());
676 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
677 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
678 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
679 mSurfaceControl.setPosition(0, 0);
680 mSurface.copyFrom(mSurfaceControl);
681
Svet Ganovb21df802014-09-01 19:06:33 -0700682 mAnimationController = new AnimationController(context,
683 mWindowManagerService.mH.getLooper());
684
Svetoslav8e3feb12014-02-24 13:46:47 -0800685 TypedValue typedValue = new TypedValue();
686 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
687 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700688 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800689
690 mPaint.setStyle(Paint.Style.STROKE);
691 mPaint.setStrokeWidth(mBorderWidth);
692 mPaint.setColor(borderColor);
693
Svetoslav8e3feb12014-02-24 13:46:47 -0800694 mInvalidated = true;
695 }
696
697 public void setShown(boolean shown, boolean animate) {
698 synchronized (mWindowManagerService.mWindowMap) {
699 if (mShown == shown) {
700 return;
701 }
702 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700703 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800704 if (DEBUG_VIEWPORT_WINDOW) {
705 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
706 }
707 }
708 }
709
710 @SuppressWarnings("unused")
711 // Called reflectively from an animator.
712 public int getAlpha() {
713 synchronized (mWindowManagerService.mWindowMap) {
714 return mAlpha;
715 }
716 }
717
718 public void setAlpha(int alpha) {
719 synchronized (mWindowManagerService.mWindowMap) {
720 if (mAlpha == alpha) {
721 return;
722 }
723 mAlpha = alpha;
724 invalidate(null);
725 if (DEBUG_VIEWPORT_WINDOW) {
726 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
727 }
728 }
729 }
730
731 public void setBounds(Region bounds) {
732 synchronized (mWindowManagerService.mWindowMap) {
733 if (mBounds.equals(bounds)) {
734 return;
735 }
736 mBounds.set(bounds);
737 invalidate(mDirtyRect);
738 if (DEBUG_VIEWPORT_WINDOW) {
739 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
740 }
741 }
742 }
743
744 public void updateSize() {
745 synchronized (mWindowManagerService.mWindowMap) {
746 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
747 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
748 invalidate(mDirtyRect);
749 }
750 }
751
752 public void invalidate(Rect dirtyRect) {
753 if (dirtyRect != null) {
754 mDirtyRect.set(dirtyRect);
755 } else {
756 mDirtyRect.setEmpty();
757 }
758 mInvalidated = true;
759 mWindowManagerService.scheduleAnimationLocked();
760 }
761
762 /** NOTE: This has to be called within a surface transaction. */
763 public void drawIfNeeded() {
764 synchronized (mWindowManagerService.mWindowMap) {
765 if (!mInvalidated) {
766 return;
767 }
768 mInvalidated = false;
769 Canvas canvas = null;
770 try {
771 // Empty dirty rectangle means unspecified.
772 if (mDirtyRect.isEmpty()) {
773 mBounds.getBounds(mDirtyRect);
774 }
775 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
776 canvas = mSurface.lockCanvas(mDirtyRect);
777 if (DEBUG_VIEWPORT_WINDOW) {
778 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
779 }
780 } catch (IllegalArgumentException iae) {
781 /* ignore */
782 } catch (Surface.OutOfResourcesException oore) {
783 /* ignore */
784 }
785 if (canvas == null) {
786 return;
787 }
788 if (DEBUG_VIEWPORT_WINDOW) {
789 Slog.i(LOG_TAG, "Bounds: " + mBounds);
790 }
791 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
792 mPaint.setAlpha(mAlpha);
793 Path path = mBounds.getBoundaryPath();
794 canvas.drawPath(path, mPaint);
795
796 mSurface.unlockCanvasAndPost(canvas);
797
798 if (mAlpha > 0) {
799 mSurfaceControl.show();
800 } else {
801 mSurfaceControl.hide();
802 }
803 }
804 }
805
806 public void releaseSurface() {
807 mSurfaceControl.release();
808 mSurface.release();
809 }
Svet Ganovb21df802014-09-01 19:06:33 -0700810
811 private final class AnimationController extends Handler {
812 private static final String PROPERTY_NAME_ALPHA = "alpha";
813
814 private static final int MIN_ALPHA = 0;
815 private static final int MAX_ALPHA = 255;
816
817 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
818
819 private final ValueAnimator mShowHideFrameAnimator;
820
821 public AnimationController(Context context, Looper looper) {
822 super(looper);
823 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
824 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
825
826 Interpolator interpolator = new DecelerateInterpolator(2.5f);
827 final long longAnimationDuration = context.getResources().getInteger(
828 com.android.internal.R.integer.config_longAnimTime);
829
830 mShowHideFrameAnimator.setInterpolator(interpolator);
831 mShowHideFrameAnimator.setDuration(longAnimationDuration);
832 }
833
834 public void onFrameShownStateChanged(boolean shown, boolean animate) {
835 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
836 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
837 }
838
839 @Override
840 public void handleMessage(Message message) {
841 switch (message.what) {
842 case MSG_FRAME_SHOWN_STATE_CHANGED: {
843 final boolean shown = message.arg1 == 1;
844 final boolean animate = message.arg2 == 1;
845
846 if (animate) {
847 if (mShowHideFrameAnimator.isRunning()) {
848 mShowHideFrameAnimator.reverse();
849 } else {
850 if (shown) {
851 mShowHideFrameAnimator.start();
852 } else {
853 mShowHideFrameAnimator.reverse();
854 }
855 }
856 } else {
857 mShowHideFrameAnimator.cancel();
858 if (shown) {
859 setAlpha(MAX_ALPHA);
860 } else {
861 setAlpha(MIN_ALPHA);
862 }
863 }
864 } break;
865 }
866 }
867 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800868 }
869 }
870
871 private class MyHandler extends Handler {
872 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
873 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
874 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
875 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
876 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
877
878 public MyHandler(Looper looper) {
879 super(looper);
880 }
881
882 @Override
883 public void handleMessage(Message message) {
884 switch (message.what) {
885 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500886 final SomeArgs args = (SomeArgs) message.obj;
887 final Region magnifiedBounds = (Region) args.arg1;
888 final Region availableBounds = (Region) args.arg2;
889 mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
890 magnifiedBounds.recycle();
891 availableBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800892 } break;
893
894 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
895 SomeArgs args = (SomeArgs) message.obj;
896 final int left = args.argi1;
897 final int top = args.argi2;
898 final int right = args.argi3;
899 final int bottom = args.argi4;
900 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
901 args.recycle();
902 } break;
903
904 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
905 mCallbacks.onUserContextChanged();
906 } break;
907
908 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
909 final int rotation = message.arg1;
910 mCallbacks.onRotationChanged(rotation);
911 } break;
912
913 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
914 synchronized (mWindowManagerService.mWindowMap) {
915 if (mMagnifedViewport.isMagnifyingLocked()) {
916 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
917 mWindowManagerService.scheduleAnimationLocked();
918 }
919 }
920 } break;
921 }
922 }
923 }
924 }
925
926 /**
927 * This class encapsulates the functionality related to computing the windows
928 * reported for accessibility purposes. These windows are all windows a sighted
929 * user can see on the screen.
930 */
931 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800932 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
933 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800934
935 private static final boolean DEBUG = false;
936
937 private final SparseArray<WindowState> mTempWindowStates =
938 new SparseArray<WindowState>();
939
940 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
941
942 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
943
944 private final RectF mTempRectF = new RectF();
945
946 private final Matrix mTempMatrix = new Matrix();
947
948 private final Point mTempPoint = new Point();
949
950 private final Rect mTempRect = new Rect();
951
952 private final Region mTempRegion = new Region();
953
954 private final Region mTempRegion1 = new Region();
955
956 private final Context mContext;
957
958 private final WindowManagerService mWindowManagerService;
959
960 private final Handler mHandler;
961
962 private final WindowsForAccessibilityCallback mCallback;
963
Svetoslavf7174e82014-06-12 11:29:35 -0700964 private final long mRecurringAccessibilityEventsIntervalMillis;
965
Svetoslav8e3feb12014-02-24 13:46:47 -0800966 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
967 WindowsForAccessibilityCallback callback) {
968 mContext = windowManagerService.mContext;
969 mWindowManagerService = windowManagerService;
970 mCallback = callback;
971 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700972 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
973 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800974 computeChangedWindows();
975 }
976
Svetoslav3a0d8782014-12-04 12:50:11 -0800977 public void performComputeChangedWindowsNotLocked() {
978 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
979 computeChangedWindows();
980 }
981
Svetoslavf7174e82014-06-12 11:29:35 -0700982 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800983 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -0700984 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
985 mRecurringAccessibilityEventsIntervalMillis);
986 }
987 }
988
Svetoslav8e3feb12014-02-24 13:46:47 -0800989 public void computeChangedWindows() {
990 if (DEBUG) {
991 Slog.i(LOG_TAG, "computeChangedWindows()");
992 }
993
Svetoslav3a0d8782014-12-04 12:50:11 -0800994 boolean windowsChanged = false;
995 List<WindowInfo> windows = new ArrayList<WindowInfo>();
996
Svetoslav8e3feb12014-02-24 13:46:47 -0800997 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700998 // Do not send the windows if there is no current focus as
999 // the window manager is still looking for where to put it.
1000 // We will do the work when we get a focus change callback.
1001 if (mWindowManagerService.mCurrentFocus == null) {
1002 return;
1003 }
1004
Svetoslav8e3feb12014-02-24 13:46:47 -08001005 WindowManager windowManager = (WindowManager)
1006 mContext.getSystemService(Context.WINDOW_SERVICE);
1007 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1008 final int screenWidth = mTempPoint.x;
1009 final int screenHeight = mTempPoint.y;
1010
1011 Region unaccountedSpace = mTempRegion;
1012 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1013
1014 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1015 populateVisibleWindowsOnScreenLocked(visibleWindows);
1016
Svetoslav8e3feb12014-02-24 13:46:47 -08001017 Set<IBinder> addedWindows = mTempBinderSet;
1018 addedWindows.clear();
1019
Svetoslavf7174e82014-06-12 11:29:35 -07001020 boolean focusedWindowAdded = false;
1021
Svetoslav8e3feb12014-02-24 13:46:47 -08001022 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001023 int skipRemainingWindowsForTaskId = -1;
1024 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001025 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001026 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001027 final int flags = windowState.mAttrs.flags;
Allen Hairf20ac2c2016-02-11 17:42:59 -08001028 final Task task = windowState.getTask();
1029
1030 // If the window is part of a task that we're finished with - ignore.
1031 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1032 continue;
1033 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001034
Svetoslav3a5c7212014-10-14 09:54:26 -07001035 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001036 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001037 continue;
1038 }
1039
Alan Viverette9538eea2014-11-13 14:49:20 -08001040 // Compute the bounds in the screen.
1041 final Rect boundsInScreen = mTempRect;
1042 computeWindowBoundsInScreen(windowState, boundsInScreen);
1043
Svetoslav8e3feb12014-02-24 13:46:47 -08001044 // If the window is completely covered by other windows - ignore.
1045 if (unaccountedSpace.quickReject(boundsInScreen)) {
1046 continue;
1047 }
1048
1049 // Add windows of certain types not covered by modal windows.
1050 if (isReportedWindowType(windowState.mAttrs.type)) {
1051 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001052 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001053 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001054 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001055 if (windowState.isFocused()) {
1056 focusedWindowAdded = true;
1057 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001058 }
1059
Alan Viveretted0c73f42014-11-18 10:25:04 -08001060 // Account for the space this window takes if the window
1061 // is not an accessibility overlay which does not change
1062 // the reported windows.
1063 if (windowState.mAttrs.type !=
1064 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1065 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1066 Region.Op.REVERSE_DIFFERENCE);
1067 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001068
1069 // We figured out what is touchable for the entire screen - done.
1070 if (unaccountedSpace.isEmpty()) {
1071 break;
1072 }
1073
Allen Hairf20ac2c2016-02-11 17:42:59 -08001074 // If a window is modal it prevents other windows from being touched
Svetoslav8e3feb12014-02-24 13:46:47 -08001075 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1076 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Allen Hairf20ac2c2016-02-11 17:42:59 -08001077 if (task != null) {
1078 // If the window is associated with a particular task, we can skip the
1079 // rest of the windows for that task.
1080 skipRemainingWindowsForTasks.add(task.mTaskId);
1081 continue;
1082 } else {
1083 // If the window is not associated with a particular task, then it is
1084 // globally modal. In this case we can skip all remaining windows.
1085 break;
1086 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001087 }
1088 }
1089
Svetoslavf7174e82014-06-12 11:29:35 -07001090 // Always report the focused window.
1091 if (!focusedWindowAdded) {
1092 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1093 WindowState windowState = visibleWindows.valueAt(i);
1094 if (windowState.isFocused()) {
1095 // Compute the bounds in the screen.
1096 Rect boundsInScreen = mTempRect;
1097 computeWindowBoundsInScreen(windowState, boundsInScreen);
1098
1099 // Add the window to the ones to be reported.
1100 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1101 boundsInScreen);
1102 addedWindows.add(window.token);
1103 windows.add(window);
1104 break;
1105 }
1106 }
1107 }
1108
Svetoslav8e3feb12014-02-24 13:46:47 -08001109 // Remove child/parent references to windows that were not added.
1110 final int windowCount = windows.size();
1111 for (int i = 0; i < windowCount; i++) {
1112 WindowInfo window = windows.get(i);
1113 if (!addedWindows.contains(window.parentToken)) {
1114 window.parentToken = null;
1115 }
1116 if (window.childTokens != null) {
1117 final int childTokenCount = window.childTokens.size();
1118 for (int j = childTokenCount - 1; j >= 0; j--) {
1119 if (!addedWindows.contains(window.childTokens.get(j))) {
1120 window.childTokens.remove(j);
1121 }
1122 }
1123 // Leave the child token list if empty.
1124 }
1125 }
1126
1127 visibleWindows.clear();
1128 addedWindows.clear();
1129
1130 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001131 if (mOldWindows.size() != windows.size()) {
1132 // Different size means something changed.
1133 windowsChanged = true;
1134 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1135 // Since we always traverse windows from high to low layer
1136 // the old and new windows at the same index should be the
1137 // same, otherwise something changed.
1138 for (int i = 0; i < windowCount; i++) {
1139 WindowInfo oldWindow = mOldWindows.get(i);
1140 WindowInfo newWindow = windows.get(i);
1141 // We do not care for layer changes given the window
1142 // order does not change. This brings no new information
1143 // to the clients.
1144 if (windowChangedNoLayer(oldWindow, newWindow)) {
1145 windowsChanged = true;
1146 break;
1147 }
1148 }
1149 }
1150
1151 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001152 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001153 }
1154 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001155
1156 // Now we do not hold the lock, so send the windows over.
1157 if (windowsChanged) {
1158 if (DEBUG) {
1159 Log.i(LOG_TAG, "Windows changed:" + windows);
1160 }
1161 mCallback.onWindowsForAccessibilityChanged(windows);
1162 } else {
1163 if (DEBUG) {
1164 Log.i(LOG_TAG, "No windows changed.");
1165 }
1166 }
1167
1168 // Recycle the windows as we do not need them.
1169 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001170 }
1171
Svetoslavf7174e82014-06-12 11:29:35 -07001172 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1173 // Get the touchable frame.
1174 Region touchableRegion = mTempRegion1;
1175 windowState.getTouchableRegion(touchableRegion);
1176 Rect touchableFrame = mTempRect;
1177 touchableRegion.getBounds(touchableFrame);
1178
1179 // Move to origin as all transforms are captured by the matrix.
1180 RectF windowFrame = mTempRectF;
1181 windowFrame.set(touchableFrame);
1182 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1183
1184 // Map the frame to get what appears on the screen.
1185 Matrix matrix = mTempMatrix;
1186 populateTransformationMatrixLocked(windowState, matrix);
1187 matrix.mapRect(windowFrame);
1188
1189 // Got the bounds.
1190 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1191 (int) windowFrame.right, (int) windowFrame.bottom);
1192 }
1193
1194 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1195 Rect boundsInScreen) {
1196 WindowInfo window = WindowInfo.obtain();
1197 window.type = windowState.mAttrs.type;
1198 window.layer = windowState.mLayer;
1199 window.token = windowState.mClient.asBinder();
1200
1201 WindowState attachedWindow = windowState.mAttachedWindow;
1202 if (attachedWindow != null) {
1203 window.parentToken = attachedWindow.mClient.asBinder();
1204 }
1205
1206 window.focused = windowState.isFocused();
1207 window.boundsInScreen.set(boundsInScreen);
1208
1209 final int childCount = windowState.mChildWindows.size();
1210 if (childCount > 0) {
1211 if (window.childTokens == null) {
1212 window.childTokens = new ArrayList<IBinder>();
1213 }
1214 for (int j = 0; j < childCount; j++) {
1215 WindowState child = windowState.mChildWindows.get(j);
1216 window.childTokens.add(child.mClient.asBinder());
1217 }
1218 }
1219
1220 return window;
1221 }
1222
Svetoslav8e3feb12014-02-24 13:46:47 -08001223 private void cacheWindows(List<WindowInfo> windows) {
1224 final int oldWindowCount = mOldWindows.size();
1225 for (int i = oldWindowCount - 1; i >= 0; i--) {
1226 mOldWindows.remove(i).recycle();
1227 }
1228 final int newWindowCount = windows.size();
1229 for (int i = 0; i < newWindowCount; i++) {
1230 WindowInfo newWindow = windows.get(i);
1231 mOldWindows.add(WindowInfo.obtain(newWindow));
1232 }
1233 }
1234
1235 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1236 if (oldWindow == newWindow) {
1237 return false;
1238 }
Svetoslavf7174e82014-06-12 11:29:35 -07001239 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001240 return true;
1241 }
Svetoslavf7174e82014-06-12 11:29:35 -07001242 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001243 return true;
1244 }
1245 if (oldWindow.type != newWindow.type) {
1246 return true;
1247 }
1248 if (oldWindow.focused != newWindow.focused) {
1249 return true;
1250 }
1251 if (oldWindow.token == null) {
1252 if (newWindow.token != null) {
1253 return true;
1254 }
1255 } else if (!oldWindow.token.equals(newWindow.token)) {
1256 return true;
1257 }
1258 if (oldWindow.parentToken == null) {
1259 if (newWindow.parentToken != null) {
1260 return true;
1261 }
1262 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1263 return true;
1264 }
1265 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1266 return true;
1267 }
1268 if (oldWindow.childTokens != null && newWindow.childTokens != null
1269 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1270 return true;
1271 }
1272 return false;
1273 }
1274
Svetoslav3a0d8782014-12-04 12:50:11 -08001275 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001276 final int windowCount = windows.size();
1277 for (int i = windowCount - 1; i >= 0; i--) {
1278 windows.remove(i).recycle();
1279 }
1280 }
1281
1282 private static boolean isReportedWindowType(int windowType) {
1283 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1284 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1285 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1286 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1287 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001288 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001289 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Svetoslav8e3feb12014-02-24 13:46:47 -08001290 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1291 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1292 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1293 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1294 }
1295
1296 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1297 DisplayContent displayContent = mWindowManagerService
1298 .getDefaultDisplayContentLocked();
1299 WindowList windowList = displayContent.getWindowList();
1300 final int windowCount = windowList.size();
1301 for (int i = 0; i < windowCount; i++) {
1302 WindowState windowState = windowList.get(i);
1303 if (windowState.isVisibleLw()) {
1304 outWindows.put(windowState.mLayer, windowState);
1305 }
1306 }
1307 }
1308
1309 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001310 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001311
1312 public MyHandler(Looper looper) {
1313 super(looper, null, false);
1314 }
1315
1316 @Override
1317 @SuppressWarnings("unchecked")
1318 public void handleMessage(Message message) {
1319 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001320 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1321 computeChangedWindows();
1322 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001323 }
1324 }
1325 }
1326 }
1327}