blob: e6b649e70bdf19e35c389a9ad3929a1b225cd427 [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;
63import java.util.List;
64import java.util.Set;
65
66/**
67 * This class contains the accessibility related logic of the window manger.
68 */
69final class AccessibilityController {
70
71 private final WindowManagerService mWindowManagerService;
72
73 private static final float[] sTempFloats = new float[9];
74
75 public AccessibilityController(WindowManagerService service) {
76 mWindowManagerService = service;
77 }
78
79 private DisplayMagnifier mDisplayMagnifier;
80
81 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
82
83 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
84 if (callbacks != null) {
85 if (mDisplayMagnifier != null) {
86 throw new IllegalStateException("Magnification callbacks already set!");
87 }
88 mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
89 } else {
90 if (mDisplayMagnifier == null) {
91 throw new IllegalStateException("Magnification callbacks already cleared!");
92 }
93 mDisplayMagnifier.destroyLocked();
94 mDisplayMagnifier = null;
95 }
96 }
97
98 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
99 if (callback != null) {
100 if (mWindowsForAccessibilityObserver != null) {
101 throw new IllegalStateException(
102 "Windows for accessibility callback already set!");
103 }
104 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
105 mWindowManagerService, callback);
106 } else {
107 if (mWindowsForAccessibilityObserver == null) {
108 throw new IllegalStateException(
109 "Windows for accessibility callback already cleared!");
110 }
111 mWindowsForAccessibilityObserver = null;
112 }
113 }
114
115 public void setMagnificationSpecLocked(MagnificationSpec spec) {
116 if (mDisplayMagnifier != null) {
117 mDisplayMagnifier.setMagnificationSpecLocked(spec);
118 }
119 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700120 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800121 }
122 }
123
Svetoslavf7174e82014-06-12 11:29:35 -0700124 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800125 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700126 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800127 }
128 // Not relevant for the window observer.
129 }
130
131 public void onWindowLayersChangedLocked() {
132 if (mDisplayMagnifier != null) {
133 mDisplayMagnifier.onWindowLayersChangedLocked();
134 }
135 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700136 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800137 }
138 }
139
140 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
141 if (mDisplayMagnifier != null) {
142 mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
143 }
144 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700145 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800146 }
147 }
148
149 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
150 if (mDisplayMagnifier != null) {
151 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
152 }
153 // Not relevant for the window observer.
154 }
155
156 public void onWindowTransitionLocked(WindowState windowState, int transition) {
157 if (mDisplayMagnifier != null) {
158 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
159 }
160 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700161 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800162 }
163 }
164
Svetoslav3a0d8782014-12-04 12:50:11 -0800165 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800166 // Not relevant for the display magnifier.
167
Svetoslav3a0d8782014-12-04 12:50:11 -0800168 WindowsForAccessibilityObserver observer = null;
169 synchronized (mWindowManagerService) {
170 observer = mWindowsForAccessibilityObserver;
171 }
172 if (observer != null) {
173 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800174 }
175 }
176
Svetoslav4604abc2014-06-10 18:59:30 -0700177
Svetoslavf7174e82014-06-12 11:29:35 -0700178 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700179 // Not relevant for the display magnifier.
180
181 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700182 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700183 }
184 }
185
Svetoslav8e3feb12014-02-24 13:46:47 -0800186 /** NOTE: This has to be called within a surface transaction. */
187 public void drawMagnifiedRegionBorderIfNeededLocked() {
188 if (mDisplayMagnifier != null) {
189 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
190 }
191 // Not relevant for the window observer.
192 }
193
194 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
195 if (mDisplayMagnifier != null) {
196 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
197 }
198 return null;
199 }
200
201 public boolean hasCallbacksLocked() {
202 return (mDisplayMagnifier != null
203 || mWindowsForAccessibilityObserver != null);
204 }
205
206 private static void populateTransformationMatrixLocked(WindowState windowState,
207 Matrix outMatrix) {
208 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
209 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
210 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
211 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
Filip Gruszczynski2a6a2c22015-10-14 12:00:53 -0700212 sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
213 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
Svetoslav8e3feb12014-02-24 13:46:47 -0800214 sTempFloats[Matrix.MPERSP_0] = 0;
215 sTempFloats[Matrix.MPERSP_1] = 0;
216 sTempFloats[Matrix.MPERSP_2] = 1;
217 outMatrix.setValues(sTempFloats);
218 }
219
220 /**
221 * This class encapsulates the functionality related to display magnification.
222 */
223 private static final class DisplayMagnifier {
224
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800225 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800226
227 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
228 private static final boolean DEBUG_ROTATION = false;
229 private static final boolean DEBUG_LAYERS = false;
230 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
231 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
232
233 private final Rect mTempRect1 = new Rect();
234 private final Rect mTempRect2 = new Rect();
235
236 private final Region mTempRegion1 = new Region();
237 private final Region mTempRegion2 = new Region();
238 private final Region mTempRegion3 = new Region();
239 private final Region mTempRegion4 = new Region();
240
241 private final Context mContext;
242 private final WindowManagerService mWindowManagerService;
243 private final MagnifiedViewport mMagnifedViewport;
244 private final Handler mHandler;
245
246 private final MagnificationCallbacks mCallbacks;
247
248 private final long mLongAnimationDuration;
249
250 public DisplayMagnifier(WindowManagerService windowManagerService,
251 MagnificationCallbacks callbacks) {
252 mContext = windowManagerService.mContext;
253 mWindowManagerService = windowManagerService;
254 mCallbacks = callbacks;
255 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
256 mMagnifedViewport = new MagnifiedViewport();
257 mLongAnimationDuration = mContext.getResources().getInteger(
258 com.android.internal.R.integer.config_longAnimTime);
259 }
260
261 public void setMagnificationSpecLocked(MagnificationSpec spec) {
262 mMagnifedViewport.updateMagnificationSpecLocked(spec);
263 mMagnifedViewport.recomputeBoundsLocked();
264 mWindowManagerService.scheduleAnimationLocked();
265 }
266
Svetoslavf7174e82014-06-12 11:29:35 -0700267 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800268 if (DEBUG_RECTANGLE_REQUESTED) {
269 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
270 }
271 if (!mMagnifedViewport.isMagnifyingLocked()) {
272 return;
273 }
274 Rect magnifiedRegionBounds = mTempRect2;
275 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
276 if (magnifiedRegionBounds.contains(rectangle)) {
277 return;
278 }
279 SomeArgs args = SomeArgs.obtain();
280 args.argi1 = rectangle.left;
281 args.argi2 = rectangle.top;
282 args.argi3 = rectangle.right;
283 args.argi4 = rectangle.bottom;
284 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
285 args).sendToTarget();
286 }
287
288 public void onWindowLayersChangedLocked() {
289 if (DEBUG_LAYERS) {
290 Slog.i(LOG_TAG, "Layers changed.");
291 }
292 mMagnifedViewport.recomputeBoundsLocked();
293 mWindowManagerService.scheduleAnimationLocked();
294 }
295
296 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
297 if (DEBUG_ROTATION) {
298 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
299 + " displayId: " + displayContent.getDisplayId());
300 }
301 mMagnifedViewport.onRotationChangedLocked();
302 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
303 }
304
305 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
306 if (DEBUG_WINDOW_TRANSITIONS) {
307 Slog.i(LOG_TAG, "Window transition: "
308 + AppTransition.appTransitionToString(transition)
309 + " displayId: " + windowState.getDisplayId());
310 }
311 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
312 if (magnifying) {
313 switch (transition) {
314 case AppTransition.TRANSIT_ACTIVITY_OPEN:
315 case AppTransition.TRANSIT_TASK_OPEN:
316 case AppTransition.TRANSIT_TASK_TO_FRONT:
317 case AppTransition.TRANSIT_WALLPAPER_OPEN:
318 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
319 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
320 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
321 }
322 }
323 }
324 }
325
326 public void onWindowTransitionLocked(WindowState windowState, int transition) {
327 if (DEBUG_WINDOW_TRANSITIONS) {
328 Slog.i(LOG_TAG, "Window transition: "
329 + AppTransition.appTransitionToString(transition)
330 + " displayId: " + windowState.getDisplayId());
331 }
332 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
333 final int type = windowState.mAttrs.type;
334 switch (transition) {
335 case WindowManagerPolicy.TRANSIT_ENTER:
336 case WindowManagerPolicy.TRANSIT_SHOW: {
337 if (!magnifying) {
338 break;
339 }
340 switch (type) {
341 case WindowManager.LayoutParams.TYPE_APPLICATION:
342 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
343 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
344 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700345 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800346 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
347 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
348 case WindowManager.LayoutParams.TYPE_PHONE:
349 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
350 case WindowManager.LayoutParams.TYPE_TOAST:
351 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
352 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
353 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
354 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
355 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
356 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500357 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200358 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800359 Rect magnifiedRegionBounds = mTempRect2;
360 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
361 magnifiedRegionBounds);
362 Rect touchableRegionBounds = mTempRect1;
363 windowState.getTouchableRegion(mTempRegion1);
364 mTempRegion1.getBounds(touchableRegionBounds);
365 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
366 mCallbacks.onRectangleOnScreenRequested(
367 touchableRegionBounds.left,
368 touchableRegionBounds.top,
369 touchableRegionBounds.right,
370 touchableRegionBounds.bottom);
371 }
372 } break;
373 } break;
374 }
375 }
376 }
377
378 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
379 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
380 if (spec != null && !spec.isNop()) {
381 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
382 final int windowType = windowState.mAttrs.type;
383 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
384 && !policy.canMagnifyWindow(windowType)) {
385 return null;
386 }
387 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
388 return null;
389 }
390 }
391 return spec;
392 }
393
394 public void destroyLocked() {
395 mMagnifedViewport.destroyWindow();
396 }
397
398 /** NOTE: This has to be called within a surface transaction. */
399 public void drawMagnifiedRegionBorderIfNeededLocked() {
400 mMagnifedViewport.drawWindowIfNeededLocked();
401 }
402
403 private final class MagnifiedViewport {
404
Svetoslav8e3feb12014-02-24 13:46:47 -0800405 private final SparseArray<WindowState> mTempWindowStates =
406 new SparseArray<WindowState>();
407
408 private final RectF mTempRectF = new RectF();
409
410 private final Point mTempPoint = new Point();
411
412 private final Matrix mTempMatrix = new Matrix();
413
414 private final Region mMagnifiedBounds = new Region();
415 private final Region mOldMagnifiedBounds = new Region();
Alan Viverette214fb682015-11-17 09:47:11 -0500416 private final Region mOldAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800417
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800418 private final Path mCircularPath;
419
Svetoslav8e3feb12014-02-24 13:46:47 -0800420 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
421
422 private final WindowManager mWindowManager;
423
Svetoslav7505e332014-08-22 12:14:28 -0700424 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800425 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700426 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800427
428 private final ViewportWindow mWindow;
429
430 private boolean mFullRedrawNeeded;
431
432 public MagnifiedViewport() {
433 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800434 mBorderWidth = mContext.getResources().getDimension(
435 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700436 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
437 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800438 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800439
Adam Powell01f280d2015-05-18 16:07:42 -0700440 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800441 mCircularPath = new Path();
442 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
443 final int centerXY = mTempPoint.x / 2;
444 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
445 } else {
446 mCircularPath = null;
447 }
448
Svetoslav8e3feb12014-02-24 13:46:47 -0800449 recomputeBoundsLocked();
450 }
451
452 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
453 if (spec != null) {
454 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
455 } else {
456 mMagnificationSpec.clear();
457 }
458 // If this message is pending we are in a rotation animation and do not want
459 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700460 if (!mHandler.hasMessages(
461 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800462 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
463 }
464 }
465
466 public void recomputeBoundsLocked() {
467 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
468 final int screenWidth = mTempPoint.x;
469 final int screenHeight = mTempPoint.y;
470
471 Region magnifiedBounds = mMagnifiedBounds;
472 magnifiedBounds.set(0, 0, 0, 0);
473
474 Region availableBounds = mTempRegion1;
475 availableBounds.set(0, 0, screenWidth, screenHeight);
476
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800477 if (mCircularPath != null) {
478 availableBounds.setPath(mCircularPath, availableBounds);
479 }
480
Svetoslav8e3feb12014-02-24 13:46:47 -0800481 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700482 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800483
484 SparseArray<WindowState> visibleWindows = mTempWindowStates;
485 visibleWindows.clear();
486 populateWindowsOnScreenLocked(visibleWindows);
487
488 final int visibleWindowCount = visibleWindows.size();
489 for (int i = visibleWindowCount - 1; i >= 0; i--) {
490 WindowState windowState = visibleWindows.valueAt(i);
491 if (windowState.mAttrs.type == WindowManager
492 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
493 continue;
494 }
495
496 Region windowBounds = mTempRegion2;
497 Matrix matrix = mTempMatrix;
498 populateTransformationMatrixLocked(windowState, matrix);
499 RectF windowFrame = mTempRectF;
500
501 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
502 windowFrame.set(windowState.mFrame);
503 windowFrame.offset(-windowFrame.left, -windowFrame.top);
504 matrix.mapRect(windowFrame);
505 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
506 (int) windowFrame.right, (int) windowFrame.bottom);
507 magnifiedBounds.op(windowBounds, Region.Op.UNION);
508 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
509 } else {
510 Region touchableRegion = mTempRegion3;
511 windowState.getTouchableRegion(touchableRegion);
512 Rect touchableFrame = mTempRect1;
513 touchableRegion.getBounds(touchableFrame);
514 windowFrame.set(touchableFrame);
515 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
516 matrix.mapRect(windowFrame);
517 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
518 (int) windowFrame.right, (int) windowFrame.bottom);
519 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
520 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
521 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
522 }
523
524 Region accountedBounds = mTempRegion2;
525 accountedBounds.set(magnifiedBounds);
526 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
527 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
528
529 if (accountedBounds.isRect()) {
530 Rect accountedFrame = mTempRect1;
531 accountedBounds.getBounds(accountedFrame);
532 if (accountedFrame.width() == screenWidth
533 && accountedFrame.height() == screenHeight) {
534 break;
535 }
536 }
537 }
538
539 visibleWindows.clear();
540
Svetoslav7505e332014-08-22 12:14:28 -0700541 magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
542 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800543 Region.Op.INTERSECT);
544
Alan Viverette214fb682015-11-17 09:47:11 -0500545 final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(magnifiedBounds);
546 final boolean availableChanged = !mOldAvailableBounds.equals(availableBounds);
547 if (magnifiedChanged || availableChanged) {
548 if (magnifiedChanged) {
549 mWindow.setBounds(magnifiedBounds);
550 Rect dirtyRect = mTempRect1;
551 if (mFullRedrawNeeded) {
552 mFullRedrawNeeded = false;
553 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
554 screenWidth - mDrawBorderInset,
555 screenHeight - mDrawBorderInset);
556 mWindow.invalidate(dirtyRect);
557 } else {
558 Region dirtyRegion = mTempRegion3;
559 dirtyRegion.set(magnifiedBounds);
560 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
561 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
562 dirtyRegion.getBounds(dirtyRect);
563 mWindow.invalidate(dirtyRect);
564 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800565
Alan Viverette214fb682015-11-17 09:47:11 -0500566 mOldMagnifiedBounds.set(magnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800567 }
568
Alan Viverette214fb682015-11-17 09:47:11 -0500569 if (availableChanged) {
570 mOldAvailableBounds.set(availableBounds);
571 }
572
573 final SomeArgs args = SomeArgs.obtain();
574 args.arg1 = Region.obtain(magnifiedBounds);
575 args.arg2 = Region.obtain(availableBounds);
576 mHandler.obtainMessage(
577 MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800578 }
579 }
580
581 public void onRotationChangedLocked() {
582 // If we are magnifying, hide the magnified border window immediately so
583 // the user does not see strange artifacts during rotation. The screenshot
584 // used for rotation has already the border. After the rotation is complete
585 // we will show the border.
586 if (isMagnifyingLocked()) {
587 setMagnifiedRegionBorderShownLocked(false, false);
588 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700589 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800590 Message message = mHandler.obtainMessage(
591 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
592 mHandler.sendMessageDelayed(message, delay);
593 }
594 recomputeBoundsLocked();
595 mWindow.updateSize();
596 }
597
598 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
599 if (shown) {
600 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700601 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800602 }
603 mWindow.setShown(shown, animate);
604 }
605
606 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
607 MagnificationSpec spec = mMagnificationSpec;
608 mMagnifiedBounds.getBounds(rect);
609 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
610 rect.scale(1.0f / spec.scale);
611 }
612
613 public boolean isMagnifyingLocked() {
614 return mMagnificationSpec.scale > 1.0f;
615 }
616
617 public MagnificationSpec getMagnificationSpecLocked() {
618 return mMagnificationSpec;
619 }
620
621 /** NOTE: This has to be called within a surface transaction. */
622 public void drawWindowIfNeededLocked() {
623 recomputeBoundsLocked();
624 mWindow.drawIfNeeded();
625 }
626
627 public void destroyWindow() {
628 mWindow.releaseSurface();
629 }
630
631 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
632 DisplayContent displayContent = mWindowManagerService
633 .getDefaultDisplayContentLocked();
634 WindowList windowList = displayContent.getWindowList();
635 final int windowCount = windowList.size();
636 for (int i = 0; i < windowCount; i++) {
637 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800638 if (windowState.isOnScreen() &&
639 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800640 outWindows.put(windowState.mLayer, windowState);
641 }
642 }
643 }
644
645 private final class ViewportWindow {
646 private static final String SURFACE_TITLE = "Magnification Overlay";
647
Svetoslav8e3feb12014-02-24 13:46:47 -0800648 private final Region mBounds = new Region();
649 private final Rect mDirtyRect = new Rect();
650 private final Paint mPaint = new Paint();
651
Svetoslav8e3feb12014-02-24 13:46:47 -0800652 private final SurfaceControl mSurfaceControl;
653 private final Surface mSurface = new Surface();
654
Svet Ganovb21df802014-09-01 19:06:33 -0700655 private final AnimationController mAnimationController;
656
Svetoslav8e3feb12014-02-24 13:46:47 -0800657 private boolean mShown;
658 private int mAlpha;
659
660 private boolean mInvalidated;
661
662 public ViewportWindow(Context context) {
663 SurfaceControl surfaceControl = null;
664 try {
665 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
666 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
667 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
668 SurfaceControl.HIDDEN);
669 } catch (OutOfResourcesException oore) {
670 /* ignore */
671 }
672 mSurfaceControl = surfaceControl;
673 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
674 .getLayerStack());
675 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
676 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
677 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
678 mSurfaceControl.setPosition(0, 0);
679 mSurface.copyFrom(mSurfaceControl);
680
Svet Ganovb21df802014-09-01 19:06:33 -0700681 mAnimationController = new AnimationController(context,
682 mWindowManagerService.mH.getLooper());
683
Svetoslav8e3feb12014-02-24 13:46:47 -0800684 TypedValue typedValue = new TypedValue();
685 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
686 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700687 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800688
689 mPaint.setStyle(Paint.Style.STROKE);
690 mPaint.setStrokeWidth(mBorderWidth);
691 mPaint.setColor(borderColor);
692
Svetoslav8e3feb12014-02-24 13:46:47 -0800693 mInvalidated = true;
694 }
695
696 public void setShown(boolean shown, boolean animate) {
697 synchronized (mWindowManagerService.mWindowMap) {
698 if (mShown == shown) {
699 return;
700 }
701 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700702 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800703 if (DEBUG_VIEWPORT_WINDOW) {
704 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
705 }
706 }
707 }
708
709 @SuppressWarnings("unused")
710 // Called reflectively from an animator.
711 public int getAlpha() {
712 synchronized (mWindowManagerService.mWindowMap) {
713 return mAlpha;
714 }
715 }
716
717 public void setAlpha(int alpha) {
718 synchronized (mWindowManagerService.mWindowMap) {
719 if (mAlpha == alpha) {
720 return;
721 }
722 mAlpha = alpha;
723 invalidate(null);
724 if (DEBUG_VIEWPORT_WINDOW) {
725 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
726 }
727 }
728 }
729
730 public void setBounds(Region bounds) {
731 synchronized (mWindowManagerService.mWindowMap) {
732 if (mBounds.equals(bounds)) {
733 return;
734 }
735 mBounds.set(bounds);
736 invalidate(mDirtyRect);
737 if (DEBUG_VIEWPORT_WINDOW) {
738 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
739 }
740 }
741 }
742
743 public void updateSize() {
744 synchronized (mWindowManagerService.mWindowMap) {
745 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
746 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
747 invalidate(mDirtyRect);
748 }
749 }
750
751 public void invalidate(Rect dirtyRect) {
752 if (dirtyRect != null) {
753 mDirtyRect.set(dirtyRect);
754 } else {
755 mDirtyRect.setEmpty();
756 }
757 mInvalidated = true;
758 mWindowManagerService.scheduleAnimationLocked();
759 }
760
761 /** NOTE: This has to be called within a surface transaction. */
762 public void drawIfNeeded() {
763 synchronized (mWindowManagerService.mWindowMap) {
764 if (!mInvalidated) {
765 return;
766 }
767 mInvalidated = false;
768 Canvas canvas = null;
769 try {
770 // Empty dirty rectangle means unspecified.
771 if (mDirtyRect.isEmpty()) {
772 mBounds.getBounds(mDirtyRect);
773 }
774 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
775 canvas = mSurface.lockCanvas(mDirtyRect);
776 if (DEBUG_VIEWPORT_WINDOW) {
777 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
778 }
779 } catch (IllegalArgumentException iae) {
780 /* ignore */
781 } catch (Surface.OutOfResourcesException oore) {
782 /* ignore */
783 }
784 if (canvas == null) {
785 return;
786 }
787 if (DEBUG_VIEWPORT_WINDOW) {
788 Slog.i(LOG_TAG, "Bounds: " + mBounds);
789 }
790 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
791 mPaint.setAlpha(mAlpha);
792 Path path = mBounds.getBoundaryPath();
793 canvas.drawPath(path, mPaint);
794
795 mSurface.unlockCanvasAndPost(canvas);
796
797 if (mAlpha > 0) {
798 mSurfaceControl.show();
799 } else {
800 mSurfaceControl.hide();
801 }
802 }
803 }
804
805 public void releaseSurface() {
806 mSurfaceControl.release();
807 mSurface.release();
808 }
Svet Ganovb21df802014-09-01 19:06:33 -0700809
810 private final class AnimationController extends Handler {
811 private static final String PROPERTY_NAME_ALPHA = "alpha";
812
813 private static final int MIN_ALPHA = 0;
814 private static final int MAX_ALPHA = 255;
815
816 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
817
818 private final ValueAnimator mShowHideFrameAnimator;
819
820 public AnimationController(Context context, Looper looper) {
821 super(looper);
822 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
823 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
824
825 Interpolator interpolator = new DecelerateInterpolator(2.5f);
826 final long longAnimationDuration = context.getResources().getInteger(
827 com.android.internal.R.integer.config_longAnimTime);
828
829 mShowHideFrameAnimator.setInterpolator(interpolator);
830 mShowHideFrameAnimator.setDuration(longAnimationDuration);
831 }
832
833 public void onFrameShownStateChanged(boolean shown, boolean animate) {
834 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
835 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
836 }
837
838 @Override
839 public void handleMessage(Message message) {
840 switch (message.what) {
841 case MSG_FRAME_SHOWN_STATE_CHANGED: {
842 final boolean shown = message.arg1 == 1;
843 final boolean animate = message.arg2 == 1;
844
845 if (animate) {
846 if (mShowHideFrameAnimator.isRunning()) {
847 mShowHideFrameAnimator.reverse();
848 } else {
849 if (shown) {
850 mShowHideFrameAnimator.start();
851 } else {
852 mShowHideFrameAnimator.reverse();
853 }
854 }
855 } else {
856 mShowHideFrameAnimator.cancel();
857 if (shown) {
858 setAlpha(MAX_ALPHA);
859 } else {
860 setAlpha(MIN_ALPHA);
861 }
862 }
863 } break;
864 }
865 }
866 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800867 }
868 }
869
870 private class MyHandler extends Handler {
871 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
872 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
873 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
874 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
875 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
876
877 public MyHandler(Looper looper) {
878 super(looper);
879 }
880
881 @Override
882 public void handleMessage(Message message) {
883 switch (message.what) {
884 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500885 final SomeArgs args = (SomeArgs) message.obj;
886 final Region magnifiedBounds = (Region) args.arg1;
887 final Region availableBounds = (Region) args.arg2;
888 mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
889 magnifiedBounds.recycle();
890 availableBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800891 } break;
892
893 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
894 SomeArgs args = (SomeArgs) message.obj;
895 final int left = args.argi1;
896 final int top = args.argi2;
897 final int right = args.argi3;
898 final int bottom = args.argi4;
899 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
900 args.recycle();
901 } break;
902
903 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
904 mCallbacks.onUserContextChanged();
905 } break;
906
907 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
908 final int rotation = message.arg1;
909 mCallbacks.onRotationChanged(rotation);
910 } break;
911
912 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
913 synchronized (mWindowManagerService.mWindowMap) {
914 if (mMagnifedViewport.isMagnifyingLocked()) {
915 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
916 mWindowManagerService.scheduleAnimationLocked();
917 }
918 }
919 } break;
920 }
921 }
922 }
923 }
924
925 /**
926 * This class encapsulates the functionality related to computing the windows
927 * reported for accessibility purposes. These windows are all windows a sighted
928 * user can see on the screen.
929 */
930 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800931 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
932 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800933
934 private static final boolean DEBUG = false;
935
936 private final SparseArray<WindowState> mTempWindowStates =
937 new SparseArray<WindowState>();
938
939 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
940
941 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
942
943 private final RectF mTempRectF = new RectF();
944
945 private final Matrix mTempMatrix = new Matrix();
946
947 private final Point mTempPoint = new Point();
948
949 private final Rect mTempRect = new Rect();
950
951 private final Region mTempRegion = new Region();
952
953 private final Region mTempRegion1 = new Region();
954
955 private final Context mContext;
956
957 private final WindowManagerService mWindowManagerService;
958
959 private final Handler mHandler;
960
961 private final WindowsForAccessibilityCallback mCallback;
962
Svetoslavf7174e82014-06-12 11:29:35 -0700963 private final long mRecurringAccessibilityEventsIntervalMillis;
964
Svetoslav8e3feb12014-02-24 13:46:47 -0800965 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
966 WindowsForAccessibilityCallback callback) {
967 mContext = windowManagerService.mContext;
968 mWindowManagerService = windowManagerService;
969 mCallback = callback;
970 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700971 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
972 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800973 computeChangedWindows();
974 }
975
Svetoslav3a0d8782014-12-04 12:50:11 -0800976 public void performComputeChangedWindowsNotLocked() {
977 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
978 computeChangedWindows();
979 }
980
Svetoslavf7174e82014-06-12 11:29:35 -0700981 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800982 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -0700983 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
984 mRecurringAccessibilityEventsIntervalMillis);
985 }
986 }
987
Svetoslav8e3feb12014-02-24 13:46:47 -0800988 public void computeChangedWindows() {
989 if (DEBUG) {
990 Slog.i(LOG_TAG, "computeChangedWindows()");
991 }
992
Svetoslav3a0d8782014-12-04 12:50:11 -0800993 boolean windowsChanged = false;
994 List<WindowInfo> windows = new ArrayList<WindowInfo>();
995
Svetoslav8e3feb12014-02-24 13:46:47 -0800996 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700997 // Do not send the windows if there is no current focus as
998 // the window manager is still looking for where to put it.
999 // We will do the work when we get a focus change callback.
1000 if (mWindowManagerService.mCurrentFocus == null) {
1001 return;
1002 }
1003
Svetoslav8e3feb12014-02-24 13:46:47 -08001004 WindowManager windowManager = (WindowManager)
1005 mContext.getSystemService(Context.WINDOW_SERVICE);
1006 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1007 final int screenWidth = mTempPoint.x;
1008 final int screenHeight = mTempPoint.y;
1009
1010 Region unaccountedSpace = mTempRegion;
1011 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1012
1013 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1014 populateVisibleWindowsOnScreenLocked(visibleWindows);
1015
Svetoslav8e3feb12014-02-24 13:46:47 -08001016 Set<IBinder> addedWindows = mTempBinderSet;
1017 addedWindows.clear();
1018
Svetoslavf7174e82014-06-12 11:29:35 -07001019 boolean focusedWindowAdded = false;
1020
Svetoslav8e3feb12014-02-24 13:46:47 -08001021 final int visibleWindowCount = visibleWindows.size();
1022 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001023 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001024 final int flags = windowState.mAttrs.flags;
1025
Svetoslav3a5c7212014-10-14 09:54:26 -07001026 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001027 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001028 continue;
1029 }
1030
Alan Viverette9538eea2014-11-13 14:49:20 -08001031 // Compute the bounds in the screen.
1032 final Rect boundsInScreen = mTempRect;
1033 computeWindowBoundsInScreen(windowState, boundsInScreen);
1034
Svetoslav8e3feb12014-02-24 13:46:47 -08001035 // If the window is completely covered by other windows - ignore.
1036 if (unaccountedSpace.quickReject(boundsInScreen)) {
1037 continue;
1038 }
1039
1040 // Add windows of certain types not covered by modal windows.
1041 if (isReportedWindowType(windowState.mAttrs.type)) {
1042 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001043 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001044 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001045 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001046 if (windowState.isFocused()) {
1047 focusedWindowAdded = true;
1048 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001049 }
1050
Alan Viveretted0c73f42014-11-18 10:25:04 -08001051 // Account for the space this window takes if the window
1052 // is not an accessibility overlay which does not change
1053 // the reported windows.
1054 if (windowState.mAttrs.type !=
1055 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1056 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1057 Region.Op.REVERSE_DIFFERENCE);
1058 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001059
1060 // We figured out what is touchable for the entire screen - done.
1061 if (unaccountedSpace.isEmpty()) {
1062 break;
1063 }
1064
1065 // If a window is modal, no other below can be touched - done.
1066 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1067 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
1068 break;
1069 }
1070 }
1071
Svetoslavf7174e82014-06-12 11:29:35 -07001072 // Always report the focused window.
1073 if (!focusedWindowAdded) {
1074 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1075 WindowState windowState = visibleWindows.valueAt(i);
1076 if (windowState.isFocused()) {
1077 // Compute the bounds in the screen.
1078 Rect boundsInScreen = mTempRect;
1079 computeWindowBoundsInScreen(windowState, boundsInScreen);
1080
1081 // Add the window to the ones to be reported.
1082 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1083 boundsInScreen);
1084 addedWindows.add(window.token);
1085 windows.add(window);
1086 break;
1087 }
1088 }
1089 }
1090
Svetoslav8e3feb12014-02-24 13:46:47 -08001091 // Remove child/parent references to windows that were not added.
1092 final int windowCount = windows.size();
1093 for (int i = 0; i < windowCount; i++) {
1094 WindowInfo window = windows.get(i);
1095 if (!addedWindows.contains(window.parentToken)) {
1096 window.parentToken = null;
1097 }
1098 if (window.childTokens != null) {
1099 final int childTokenCount = window.childTokens.size();
1100 for (int j = childTokenCount - 1; j >= 0; j--) {
1101 if (!addedWindows.contains(window.childTokens.get(j))) {
1102 window.childTokens.remove(j);
1103 }
1104 }
1105 // Leave the child token list if empty.
1106 }
1107 }
1108
1109 visibleWindows.clear();
1110 addedWindows.clear();
1111
1112 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001113 if (mOldWindows.size() != windows.size()) {
1114 // Different size means something changed.
1115 windowsChanged = true;
1116 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1117 // Since we always traverse windows from high to low layer
1118 // the old and new windows at the same index should be the
1119 // same, otherwise something changed.
1120 for (int i = 0; i < windowCount; i++) {
1121 WindowInfo oldWindow = mOldWindows.get(i);
1122 WindowInfo newWindow = windows.get(i);
1123 // We do not care for layer changes given the window
1124 // order does not change. This brings no new information
1125 // to the clients.
1126 if (windowChangedNoLayer(oldWindow, newWindow)) {
1127 windowsChanged = true;
1128 break;
1129 }
1130 }
1131 }
1132
1133 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001134 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001135 }
1136 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001137
1138 // Now we do not hold the lock, so send the windows over.
1139 if (windowsChanged) {
1140 if (DEBUG) {
1141 Log.i(LOG_TAG, "Windows changed:" + windows);
1142 }
1143 mCallback.onWindowsForAccessibilityChanged(windows);
1144 } else {
1145 if (DEBUG) {
1146 Log.i(LOG_TAG, "No windows changed.");
1147 }
1148 }
1149
1150 // Recycle the windows as we do not need them.
1151 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001152 }
1153
Svetoslavf7174e82014-06-12 11:29:35 -07001154 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1155 // Get the touchable frame.
1156 Region touchableRegion = mTempRegion1;
1157 windowState.getTouchableRegion(touchableRegion);
1158 Rect touchableFrame = mTempRect;
1159 touchableRegion.getBounds(touchableFrame);
1160
1161 // Move to origin as all transforms are captured by the matrix.
1162 RectF windowFrame = mTempRectF;
1163 windowFrame.set(touchableFrame);
1164 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1165
1166 // Map the frame to get what appears on the screen.
1167 Matrix matrix = mTempMatrix;
1168 populateTransformationMatrixLocked(windowState, matrix);
1169 matrix.mapRect(windowFrame);
1170
1171 // Got the bounds.
1172 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1173 (int) windowFrame.right, (int) windowFrame.bottom);
1174 }
1175
1176 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1177 Rect boundsInScreen) {
1178 WindowInfo window = WindowInfo.obtain();
1179 window.type = windowState.mAttrs.type;
1180 window.layer = windowState.mLayer;
1181 window.token = windowState.mClient.asBinder();
1182
1183 WindowState attachedWindow = windowState.mAttachedWindow;
1184 if (attachedWindow != null) {
1185 window.parentToken = attachedWindow.mClient.asBinder();
1186 }
1187
1188 window.focused = windowState.isFocused();
1189 window.boundsInScreen.set(boundsInScreen);
1190
1191 final int childCount = windowState.mChildWindows.size();
1192 if (childCount > 0) {
1193 if (window.childTokens == null) {
1194 window.childTokens = new ArrayList<IBinder>();
1195 }
1196 for (int j = 0; j < childCount; j++) {
1197 WindowState child = windowState.mChildWindows.get(j);
1198 window.childTokens.add(child.mClient.asBinder());
1199 }
1200 }
1201
1202 return window;
1203 }
1204
Svetoslav8e3feb12014-02-24 13:46:47 -08001205 private void cacheWindows(List<WindowInfo> windows) {
1206 final int oldWindowCount = mOldWindows.size();
1207 for (int i = oldWindowCount - 1; i >= 0; i--) {
1208 mOldWindows.remove(i).recycle();
1209 }
1210 final int newWindowCount = windows.size();
1211 for (int i = 0; i < newWindowCount; i++) {
1212 WindowInfo newWindow = windows.get(i);
1213 mOldWindows.add(WindowInfo.obtain(newWindow));
1214 }
1215 }
1216
1217 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1218 if (oldWindow == newWindow) {
1219 return false;
1220 }
Svetoslavf7174e82014-06-12 11:29:35 -07001221 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001222 return true;
1223 }
Svetoslavf7174e82014-06-12 11:29:35 -07001224 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001225 return true;
1226 }
1227 if (oldWindow.type != newWindow.type) {
1228 return true;
1229 }
1230 if (oldWindow.focused != newWindow.focused) {
1231 return true;
1232 }
1233 if (oldWindow.token == null) {
1234 if (newWindow.token != null) {
1235 return true;
1236 }
1237 } else if (!oldWindow.token.equals(newWindow.token)) {
1238 return true;
1239 }
1240 if (oldWindow.parentToken == null) {
1241 if (newWindow.parentToken != null) {
1242 return true;
1243 }
1244 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1245 return true;
1246 }
1247 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1248 return true;
1249 }
1250 if (oldWindow.childTokens != null && newWindow.childTokens != null
1251 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1252 return true;
1253 }
1254 return false;
1255 }
1256
Svetoslav3a0d8782014-12-04 12:50:11 -08001257 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001258 final int windowCount = windows.size();
1259 for (int i = windowCount - 1; i >= 0; i--) {
1260 windows.remove(i).recycle();
1261 }
1262 }
1263
1264 private static boolean isReportedWindowType(int windowType) {
1265 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1266 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1267 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1268 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1269 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001270 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001271 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Svetoslav8e3feb12014-02-24 13:46:47 -08001272 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1273 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1274 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1275 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1276 }
1277
1278 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1279 DisplayContent displayContent = mWindowManagerService
1280 .getDefaultDisplayContentLocked();
1281 WindowList windowList = displayContent.getWindowList();
1282 final int windowCount = windowList.size();
1283 for (int i = 0; i < windowCount; i++) {
1284 WindowState windowState = windowList.get(i);
1285 if (windowState.isVisibleLw()) {
1286 outWindows.put(windowState.mLayer, windowState);
1287 }
1288 }
1289 }
1290
1291 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001292 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001293
1294 public MyHandler(Looper looper) {
1295 super(looper, null, false);
1296 }
1297
1298 @Override
1299 @SuppressWarnings("unchecked")
1300 public void handleMessage(Message message) {
1301 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001302 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1303 computeChangedWindows();
1304 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001305 }
1306 }
1307 }
1308 }
1309}