blob: a4b42763b1ce09f9c77ddd33a511d106aa596012 [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
19import android.animation.ObjectAnimator;
20import android.animation.ValueAnimator;
21import android.app.Service;
22import android.content.Context;
23import android.graphics.Canvas;
24import android.graphics.Color;
25import android.graphics.Matrix;
26import android.graphics.Paint;
27import android.graphics.Path;
28import android.graphics.PixelFormat;
29import android.graphics.Point;
30import android.graphics.PorterDuff.Mode;
31import android.graphics.Rect;
32import android.graphics.RectF;
33import android.graphics.Region;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Looper;
37import android.os.Message;
38import android.util.ArraySet;
39import android.util.Log;
40import android.util.Slog;
41import android.util.SparseArray;
42import android.util.TypedValue;
43import android.view.MagnificationSpec;
44import android.view.Surface;
45import android.view.Surface.OutOfResourcesException;
46import android.view.SurfaceControl;
Svetoslavf7174e82014-06-12 11:29:35 -070047import android.view.ViewConfiguration;
Svetoslav8e3feb12014-02-24 13:46:47 -080048import android.view.WindowInfo;
49import android.view.WindowManager;
50import android.view.WindowManagerInternal.MagnificationCallbacks;
51import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
52import android.view.WindowManagerPolicy;
53import android.view.animation.DecelerateInterpolator;
54import android.view.animation.Interpolator;
55
56import com.android.internal.R;
57import com.android.internal.os.SomeArgs;
58
59import java.util.ArrayList;
60import java.util.List;
61import java.util.Set;
62
63/**
64 * This class contains the accessibility related logic of the window manger.
65 */
66final class AccessibilityController {
67
68 private final WindowManagerService mWindowManagerService;
69
70 private static final float[] sTempFloats = new float[9];
71
72 public AccessibilityController(WindowManagerService service) {
73 mWindowManagerService = service;
74 }
75
76 private DisplayMagnifier mDisplayMagnifier;
77
78 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
79
80 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
81 if (callbacks != null) {
82 if (mDisplayMagnifier != null) {
83 throw new IllegalStateException("Magnification callbacks already set!");
84 }
85 mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
86 } else {
87 if (mDisplayMagnifier == null) {
88 throw new IllegalStateException("Magnification callbacks already cleared!");
89 }
90 mDisplayMagnifier.destroyLocked();
91 mDisplayMagnifier = null;
92 }
93 }
94
95 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
96 if (callback != null) {
97 if (mWindowsForAccessibilityObserver != null) {
98 throw new IllegalStateException(
99 "Windows for accessibility callback already set!");
100 }
101 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
102 mWindowManagerService, callback);
103 } else {
104 if (mWindowsForAccessibilityObserver == null) {
105 throw new IllegalStateException(
106 "Windows for accessibility callback already cleared!");
107 }
108 mWindowsForAccessibilityObserver = null;
109 }
110 }
111
112 public void setMagnificationSpecLocked(MagnificationSpec spec) {
113 if (mDisplayMagnifier != null) {
114 mDisplayMagnifier.setMagnificationSpecLocked(spec);
115 }
116 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700117 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800118 }
119 }
120
Svetoslavf7174e82014-06-12 11:29:35 -0700121 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800122 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700123 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800124 }
125 // Not relevant for the window observer.
126 }
127
128 public void onWindowLayersChangedLocked() {
129 if (mDisplayMagnifier != null) {
130 mDisplayMagnifier.onWindowLayersChangedLocked();
131 }
132 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700133 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800134 }
135 }
136
137 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
138 if (mDisplayMagnifier != null) {
139 mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
140 }
141 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700142 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800143 }
144 }
145
146 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
147 if (mDisplayMagnifier != null) {
148 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
149 }
150 // Not relevant for the window observer.
151 }
152
153 public void onWindowTransitionLocked(WindowState windowState, int transition) {
154 if (mDisplayMagnifier != null) {
155 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
156 }
157 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700158 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800159 }
160 }
161
Svetoslav3a0d8782014-12-04 12:50:11 -0800162 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800163 // Not relevant for the display magnifier.
164
Svetoslav3a0d8782014-12-04 12:50:11 -0800165 WindowsForAccessibilityObserver observer = null;
166 synchronized (mWindowManagerService) {
167 observer = mWindowsForAccessibilityObserver;
168 }
169 if (observer != null) {
170 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800171 }
172 }
173
Svetoslav4604abc2014-06-10 18:59:30 -0700174
Svetoslavf7174e82014-06-12 11:29:35 -0700175 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700176 // Not relevant for the display magnifier.
177
178 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700179 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700180 }
181 }
182
Svetoslav8e3feb12014-02-24 13:46:47 -0800183 /** NOTE: This has to be called within a surface transaction. */
184 public void drawMagnifiedRegionBorderIfNeededLocked() {
185 if (mDisplayMagnifier != null) {
186 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
187 }
188 // Not relevant for the window observer.
189 }
190
191 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
192 if (mDisplayMagnifier != null) {
193 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
194 }
195 return null;
196 }
197
198 public boolean hasCallbacksLocked() {
199 return (mDisplayMagnifier != null
200 || mWindowsForAccessibilityObserver != null);
201 }
202
203 private static void populateTransformationMatrixLocked(WindowState windowState,
204 Matrix outMatrix) {
205 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
206 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
207 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
208 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
Filip Gruszczynski2a6a2c22015-10-14 12:00:53 -0700209 sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
210 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
Svetoslav8e3feb12014-02-24 13:46:47 -0800211 sTempFloats[Matrix.MPERSP_0] = 0;
212 sTempFloats[Matrix.MPERSP_1] = 0;
213 sTempFloats[Matrix.MPERSP_2] = 1;
214 outMatrix.setValues(sTempFloats);
215 }
216
217 /**
218 * This class encapsulates the functionality related to display magnification.
219 */
220 private static final class DisplayMagnifier {
221
222 private static final String LOG_TAG = "DisplayMagnifier";
223
224 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
225 private static final boolean DEBUG_ROTATION = false;
226 private static final boolean DEBUG_LAYERS = false;
227 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
228 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
229
230 private final Rect mTempRect1 = new Rect();
231 private final Rect mTempRect2 = new Rect();
232
233 private final Region mTempRegion1 = new Region();
234 private final Region mTempRegion2 = new Region();
235 private final Region mTempRegion3 = new Region();
236 private final Region mTempRegion4 = new Region();
237
238 private final Context mContext;
239 private final WindowManagerService mWindowManagerService;
240 private final MagnifiedViewport mMagnifedViewport;
241 private final Handler mHandler;
242
243 private final MagnificationCallbacks mCallbacks;
244
245 private final long mLongAnimationDuration;
246
247 public DisplayMagnifier(WindowManagerService windowManagerService,
248 MagnificationCallbacks callbacks) {
249 mContext = windowManagerService.mContext;
250 mWindowManagerService = windowManagerService;
251 mCallbacks = callbacks;
252 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
253 mMagnifedViewport = new MagnifiedViewport();
254 mLongAnimationDuration = mContext.getResources().getInteger(
255 com.android.internal.R.integer.config_longAnimTime);
256 }
257
258 public void setMagnificationSpecLocked(MagnificationSpec spec) {
259 mMagnifedViewport.updateMagnificationSpecLocked(spec);
260 mMagnifedViewport.recomputeBoundsLocked();
261 mWindowManagerService.scheduleAnimationLocked();
262 }
263
Svetoslavf7174e82014-06-12 11:29:35 -0700264 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800265 if (DEBUG_RECTANGLE_REQUESTED) {
266 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
267 }
268 if (!mMagnifedViewport.isMagnifyingLocked()) {
269 return;
270 }
271 Rect magnifiedRegionBounds = mTempRect2;
272 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
273 if (magnifiedRegionBounds.contains(rectangle)) {
274 return;
275 }
276 SomeArgs args = SomeArgs.obtain();
277 args.argi1 = rectangle.left;
278 args.argi2 = rectangle.top;
279 args.argi3 = rectangle.right;
280 args.argi4 = rectangle.bottom;
281 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
282 args).sendToTarget();
283 }
284
285 public void onWindowLayersChangedLocked() {
286 if (DEBUG_LAYERS) {
287 Slog.i(LOG_TAG, "Layers changed.");
288 }
289 mMagnifedViewport.recomputeBoundsLocked();
290 mWindowManagerService.scheduleAnimationLocked();
291 }
292
293 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
294 if (DEBUG_ROTATION) {
295 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
296 + " displayId: " + displayContent.getDisplayId());
297 }
298 mMagnifedViewport.onRotationChangedLocked();
299 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
300 }
301
302 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
303 if (DEBUG_WINDOW_TRANSITIONS) {
304 Slog.i(LOG_TAG, "Window transition: "
305 + AppTransition.appTransitionToString(transition)
306 + " displayId: " + windowState.getDisplayId());
307 }
308 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
309 if (magnifying) {
310 switch (transition) {
311 case AppTransition.TRANSIT_ACTIVITY_OPEN:
312 case AppTransition.TRANSIT_TASK_OPEN:
313 case AppTransition.TRANSIT_TASK_TO_FRONT:
314 case AppTransition.TRANSIT_WALLPAPER_OPEN:
315 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
316 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
317 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
318 }
319 }
320 }
321 }
322
323 public void onWindowTransitionLocked(WindowState windowState, int transition) {
324 if (DEBUG_WINDOW_TRANSITIONS) {
325 Slog.i(LOG_TAG, "Window transition: "
326 + AppTransition.appTransitionToString(transition)
327 + " displayId: " + windowState.getDisplayId());
328 }
329 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
330 final int type = windowState.mAttrs.type;
331 switch (transition) {
332 case WindowManagerPolicy.TRANSIT_ENTER:
333 case WindowManagerPolicy.TRANSIT_SHOW: {
334 if (!magnifying) {
335 break;
336 }
337 switch (type) {
338 case WindowManager.LayoutParams.TYPE_APPLICATION:
339 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
340 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
341 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700342 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800343 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
344 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
345 case WindowManager.LayoutParams.TYPE_PHONE:
346 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
347 case WindowManager.LayoutParams.TYPE_TOAST:
348 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
349 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
350 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
351 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
352 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
353 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500354 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200355 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800356 Rect magnifiedRegionBounds = mTempRect2;
357 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
358 magnifiedRegionBounds);
359 Rect touchableRegionBounds = mTempRect1;
360 windowState.getTouchableRegion(mTempRegion1);
361 mTempRegion1.getBounds(touchableRegionBounds);
362 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
363 mCallbacks.onRectangleOnScreenRequested(
364 touchableRegionBounds.left,
365 touchableRegionBounds.top,
366 touchableRegionBounds.right,
367 touchableRegionBounds.bottom);
368 }
369 } break;
370 } break;
371 }
372 }
373 }
374
375 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
376 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
377 if (spec != null && !spec.isNop()) {
378 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
379 final int windowType = windowState.mAttrs.type;
380 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
381 && !policy.canMagnifyWindow(windowType)) {
382 return null;
383 }
384 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
385 return null;
386 }
387 }
388 return spec;
389 }
390
391 public void destroyLocked() {
392 mMagnifedViewport.destroyWindow();
393 }
394
395 /** NOTE: This has to be called within a surface transaction. */
396 public void drawMagnifiedRegionBorderIfNeededLocked() {
397 mMagnifedViewport.drawWindowIfNeededLocked();
398 }
399
400 private final class MagnifiedViewport {
401
Svetoslav8e3feb12014-02-24 13:46:47 -0800402 private final SparseArray<WindowState> mTempWindowStates =
403 new SparseArray<WindowState>();
404
405 private final RectF mTempRectF = new RectF();
406
407 private final Point mTempPoint = new Point();
408
409 private final Matrix mTempMatrix = new Matrix();
410
411 private final Region mMagnifiedBounds = new Region();
412 private final Region mOldMagnifiedBounds = new Region();
Alan Viverette214fb682015-11-17 09:47:11 -0500413 private final Region mOldAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800414
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800415 private final Path mCircularPath;
416
Svetoslav8e3feb12014-02-24 13:46:47 -0800417 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
418
419 private final WindowManager mWindowManager;
420
Svetoslav7505e332014-08-22 12:14:28 -0700421 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800422 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700423 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800424
425 private final ViewportWindow mWindow;
426
427 private boolean mFullRedrawNeeded;
428
429 public MagnifiedViewport() {
430 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800431 mBorderWidth = mContext.getResources().getDimension(
432 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700433 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
434 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800435 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800436
Adam Powell01f280d2015-05-18 16:07:42 -0700437 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800438 mCircularPath = new Path();
439 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
440 final int centerXY = mTempPoint.x / 2;
441 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
442 } else {
443 mCircularPath = null;
444 }
445
Svetoslav8e3feb12014-02-24 13:46:47 -0800446 recomputeBoundsLocked();
447 }
448
449 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
450 if (spec != null) {
451 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
452 } else {
453 mMagnificationSpec.clear();
454 }
455 // If this message is pending we are in a rotation animation and do not want
456 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700457 if (!mHandler.hasMessages(
458 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800459 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
460 }
461 }
462
463 public void recomputeBoundsLocked() {
464 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
465 final int screenWidth = mTempPoint.x;
466 final int screenHeight = mTempPoint.y;
467
468 Region magnifiedBounds = mMagnifiedBounds;
469 magnifiedBounds.set(0, 0, 0, 0);
470
471 Region availableBounds = mTempRegion1;
472 availableBounds.set(0, 0, screenWidth, screenHeight);
473
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800474 if (mCircularPath != null) {
475 availableBounds.setPath(mCircularPath, availableBounds);
476 }
477
Svetoslav8e3feb12014-02-24 13:46:47 -0800478 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700479 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800480
481 SparseArray<WindowState> visibleWindows = mTempWindowStates;
482 visibleWindows.clear();
483 populateWindowsOnScreenLocked(visibleWindows);
484
485 final int visibleWindowCount = visibleWindows.size();
486 for (int i = visibleWindowCount - 1; i >= 0; i--) {
487 WindowState windowState = visibleWindows.valueAt(i);
488 if (windowState.mAttrs.type == WindowManager
489 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
490 continue;
491 }
492
493 Region windowBounds = mTempRegion2;
494 Matrix matrix = mTempMatrix;
495 populateTransformationMatrixLocked(windowState, matrix);
496 RectF windowFrame = mTempRectF;
497
498 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
499 windowFrame.set(windowState.mFrame);
500 windowFrame.offset(-windowFrame.left, -windowFrame.top);
501 matrix.mapRect(windowFrame);
502 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
503 (int) windowFrame.right, (int) windowFrame.bottom);
504 magnifiedBounds.op(windowBounds, Region.Op.UNION);
505 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
506 } else {
507 Region touchableRegion = mTempRegion3;
508 windowState.getTouchableRegion(touchableRegion);
509 Rect touchableFrame = mTempRect1;
510 touchableRegion.getBounds(touchableFrame);
511 windowFrame.set(touchableFrame);
512 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
513 matrix.mapRect(windowFrame);
514 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
515 (int) windowFrame.right, (int) windowFrame.bottom);
516 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
517 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
518 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
519 }
520
521 Region accountedBounds = mTempRegion2;
522 accountedBounds.set(magnifiedBounds);
523 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
524 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
525
526 if (accountedBounds.isRect()) {
527 Rect accountedFrame = mTempRect1;
528 accountedBounds.getBounds(accountedFrame);
529 if (accountedFrame.width() == screenWidth
530 && accountedFrame.height() == screenHeight) {
531 break;
532 }
533 }
534 }
535
536 visibleWindows.clear();
537
Svetoslav7505e332014-08-22 12:14:28 -0700538 magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
539 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800540 Region.Op.INTERSECT);
541
Alan Viverette214fb682015-11-17 09:47:11 -0500542 final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(magnifiedBounds);
543 final boolean availableChanged = !mOldAvailableBounds.equals(availableBounds);
544 if (magnifiedChanged || availableChanged) {
545 if (magnifiedChanged) {
546 mWindow.setBounds(magnifiedBounds);
547 Rect dirtyRect = mTempRect1;
548 if (mFullRedrawNeeded) {
549 mFullRedrawNeeded = false;
550 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
551 screenWidth - mDrawBorderInset,
552 screenHeight - mDrawBorderInset);
553 mWindow.invalidate(dirtyRect);
554 } else {
555 Region dirtyRegion = mTempRegion3;
556 dirtyRegion.set(magnifiedBounds);
557 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
558 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
559 dirtyRegion.getBounds(dirtyRect);
560 mWindow.invalidate(dirtyRect);
561 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800562
Alan Viverette214fb682015-11-17 09:47:11 -0500563 mOldMagnifiedBounds.set(magnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800564 }
565
Alan Viverette214fb682015-11-17 09:47:11 -0500566 if (availableChanged) {
567 mOldAvailableBounds.set(availableBounds);
568 }
569
570 final SomeArgs args = SomeArgs.obtain();
571 args.arg1 = Region.obtain(magnifiedBounds);
572 args.arg2 = Region.obtain(availableBounds);
573 mHandler.obtainMessage(
574 MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800575 }
576 }
577
578 public void onRotationChangedLocked() {
579 // If we are magnifying, hide the magnified border window immediately so
580 // the user does not see strange artifacts during rotation. The screenshot
581 // used for rotation has already the border. After the rotation is complete
582 // we will show the border.
583 if (isMagnifyingLocked()) {
584 setMagnifiedRegionBorderShownLocked(false, false);
585 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700586 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800587 Message message = mHandler.obtainMessage(
588 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
589 mHandler.sendMessageDelayed(message, delay);
590 }
591 recomputeBoundsLocked();
592 mWindow.updateSize();
593 }
594
595 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
596 if (shown) {
597 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700598 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800599 }
600 mWindow.setShown(shown, animate);
601 }
602
603 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
604 MagnificationSpec spec = mMagnificationSpec;
605 mMagnifiedBounds.getBounds(rect);
606 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
607 rect.scale(1.0f / spec.scale);
608 }
609
610 public boolean isMagnifyingLocked() {
611 return mMagnificationSpec.scale > 1.0f;
612 }
613
614 public MagnificationSpec getMagnificationSpecLocked() {
615 return mMagnificationSpec;
616 }
617
618 /** NOTE: This has to be called within a surface transaction. */
619 public void drawWindowIfNeededLocked() {
620 recomputeBoundsLocked();
621 mWindow.drawIfNeeded();
622 }
623
624 public void destroyWindow() {
625 mWindow.releaseSurface();
626 }
627
628 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
629 DisplayContent displayContent = mWindowManagerService
630 .getDefaultDisplayContentLocked();
631 WindowList windowList = displayContent.getWindowList();
632 final int windowCount = windowList.size();
633 for (int i = 0; i < windowCount; i++) {
634 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800635 if (windowState.isOnScreen() &&
636 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800637 outWindows.put(windowState.mLayer, windowState);
638 }
639 }
640 }
641
642 private final class ViewportWindow {
643 private static final String SURFACE_TITLE = "Magnification Overlay";
644
Svetoslav8e3feb12014-02-24 13:46:47 -0800645 private final Region mBounds = new Region();
646 private final Rect mDirtyRect = new Rect();
647 private final Paint mPaint = new Paint();
648
Svetoslav8e3feb12014-02-24 13:46:47 -0800649 private final SurfaceControl mSurfaceControl;
650 private final Surface mSurface = new Surface();
651
Svet Ganovb21df802014-09-01 19:06:33 -0700652 private final AnimationController mAnimationController;
653
Svetoslav8e3feb12014-02-24 13:46:47 -0800654 private boolean mShown;
655 private int mAlpha;
656
657 private boolean mInvalidated;
658
659 public ViewportWindow(Context context) {
660 SurfaceControl surfaceControl = null;
661 try {
662 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
663 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
664 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
665 SurfaceControl.HIDDEN);
666 } catch (OutOfResourcesException oore) {
667 /* ignore */
668 }
669 mSurfaceControl = surfaceControl;
670 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
671 .getLayerStack());
672 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
673 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
674 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
675 mSurfaceControl.setPosition(0, 0);
676 mSurface.copyFrom(mSurfaceControl);
677
Svet Ganovb21df802014-09-01 19:06:33 -0700678 mAnimationController = new AnimationController(context,
679 mWindowManagerService.mH.getLooper());
680
Svetoslav8e3feb12014-02-24 13:46:47 -0800681 TypedValue typedValue = new TypedValue();
682 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
683 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700684 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800685
686 mPaint.setStyle(Paint.Style.STROKE);
687 mPaint.setStrokeWidth(mBorderWidth);
688 mPaint.setColor(borderColor);
689
Svetoslav8e3feb12014-02-24 13:46:47 -0800690 mInvalidated = true;
691 }
692
693 public void setShown(boolean shown, boolean animate) {
694 synchronized (mWindowManagerService.mWindowMap) {
695 if (mShown == shown) {
696 return;
697 }
698 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700699 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800700 if (DEBUG_VIEWPORT_WINDOW) {
701 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
702 }
703 }
704 }
705
706 @SuppressWarnings("unused")
707 // Called reflectively from an animator.
708 public int getAlpha() {
709 synchronized (mWindowManagerService.mWindowMap) {
710 return mAlpha;
711 }
712 }
713
714 public void setAlpha(int alpha) {
715 synchronized (mWindowManagerService.mWindowMap) {
716 if (mAlpha == alpha) {
717 return;
718 }
719 mAlpha = alpha;
720 invalidate(null);
721 if (DEBUG_VIEWPORT_WINDOW) {
722 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
723 }
724 }
725 }
726
727 public void setBounds(Region bounds) {
728 synchronized (mWindowManagerService.mWindowMap) {
729 if (mBounds.equals(bounds)) {
730 return;
731 }
732 mBounds.set(bounds);
733 invalidate(mDirtyRect);
734 if (DEBUG_VIEWPORT_WINDOW) {
735 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
736 }
737 }
738 }
739
740 public void updateSize() {
741 synchronized (mWindowManagerService.mWindowMap) {
742 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
743 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
744 invalidate(mDirtyRect);
745 }
746 }
747
748 public void invalidate(Rect dirtyRect) {
749 if (dirtyRect != null) {
750 mDirtyRect.set(dirtyRect);
751 } else {
752 mDirtyRect.setEmpty();
753 }
754 mInvalidated = true;
755 mWindowManagerService.scheduleAnimationLocked();
756 }
757
758 /** NOTE: This has to be called within a surface transaction. */
759 public void drawIfNeeded() {
760 synchronized (mWindowManagerService.mWindowMap) {
761 if (!mInvalidated) {
762 return;
763 }
764 mInvalidated = false;
765 Canvas canvas = null;
766 try {
767 // Empty dirty rectangle means unspecified.
768 if (mDirtyRect.isEmpty()) {
769 mBounds.getBounds(mDirtyRect);
770 }
771 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
772 canvas = mSurface.lockCanvas(mDirtyRect);
773 if (DEBUG_VIEWPORT_WINDOW) {
774 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
775 }
776 } catch (IllegalArgumentException iae) {
777 /* ignore */
778 } catch (Surface.OutOfResourcesException oore) {
779 /* ignore */
780 }
781 if (canvas == null) {
782 return;
783 }
784 if (DEBUG_VIEWPORT_WINDOW) {
785 Slog.i(LOG_TAG, "Bounds: " + mBounds);
786 }
787 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
788 mPaint.setAlpha(mAlpha);
789 Path path = mBounds.getBoundaryPath();
790 canvas.drawPath(path, mPaint);
791
792 mSurface.unlockCanvasAndPost(canvas);
793
794 if (mAlpha > 0) {
795 mSurfaceControl.show();
796 } else {
797 mSurfaceControl.hide();
798 }
799 }
800 }
801
802 public void releaseSurface() {
803 mSurfaceControl.release();
804 mSurface.release();
805 }
Svet Ganovb21df802014-09-01 19:06:33 -0700806
807 private final class AnimationController extends Handler {
808 private static final String PROPERTY_NAME_ALPHA = "alpha";
809
810 private static final int MIN_ALPHA = 0;
811 private static final int MAX_ALPHA = 255;
812
813 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
814
815 private final ValueAnimator mShowHideFrameAnimator;
816
817 public AnimationController(Context context, Looper looper) {
818 super(looper);
819 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
820 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
821
822 Interpolator interpolator = new DecelerateInterpolator(2.5f);
823 final long longAnimationDuration = context.getResources().getInteger(
824 com.android.internal.R.integer.config_longAnimTime);
825
826 mShowHideFrameAnimator.setInterpolator(interpolator);
827 mShowHideFrameAnimator.setDuration(longAnimationDuration);
828 }
829
830 public void onFrameShownStateChanged(boolean shown, boolean animate) {
831 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
832 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
833 }
834
835 @Override
836 public void handleMessage(Message message) {
837 switch (message.what) {
838 case MSG_FRAME_SHOWN_STATE_CHANGED: {
839 final boolean shown = message.arg1 == 1;
840 final boolean animate = message.arg2 == 1;
841
842 if (animate) {
843 if (mShowHideFrameAnimator.isRunning()) {
844 mShowHideFrameAnimator.reverse();
845 } else {
846 if (shown) {
847 mShowHideFrameAnimator.start();
848 } else {
849 mShowHideFrameAnimator.reverse();
850 }
851 }
852 } else {
853 mShowHideFrameAnimator.cancel();
854 if (shown) {
855 setAlpha(MAX_ALPHA);
856 } else {
857 setAlpha(MIN_ALPHA);
858 }
859 }
860 } break;
861 }
862 }
863 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800864 }
865 }
866
867 private class MyHandler extends Handler {
868 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
869 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
870 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
871 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
872 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
873
874 public MyHandler(Looper looper) {
875 super(looper);
876 }
877
878 @Override
879 public void handleMessage(Message message) {
880 switch (message.what) {
881 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500882 final SomeArgs args = (SomeArgs) message.obj;
883 final Region magnifiedBounds = (Region) args.arg1;
884 final Region availableBounds = (Region) args.arg2;
885 mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
886 magnifiedBounds.recycle();
887 availableBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800888 } break;
889
890 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
891 SomeArgs args = (SomeArgs) message.obj;
892 final int left = args.argi1;
893 final int top = args.argi2;
894 final int right = args.argi3;
895 final int bottom = args.argi4;
896 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
897 args.recycle();
898 } break;
899
900 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
901 mCallbacks.onUserContextChanged();
902 } break;
903
904 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
905 final int rotation = message.arg1;
906 mCallbacks.onRotationChanged(rotation);
907 } break;
908
909 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
910 synchronized (mWindowManagerService.mWindowMap) {
911 if (mMagnifedViewport.isMagnifyingLocked()) {
912 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
913 mWindowManagerService.scheduleAnimationLocked();
914 }
915 }
916 } break;
917 }
918 }
919 }
920 }
921
922 /**
923 * This class encapsulates the functionality related to computing the windows
924 * reported for accessibility purposes. These windows are all windows a sighted
925 * user can see on the screen.
926 */
927 private static final class WindowsForAccessibilityObserver {
928 private static final String LOG_TAG = "WindowsForAccessibilityObserver";
929
930 private static final boolean DEBUG = false;
931
932 private final SparseArray<WindowState> mTempWindowStates =
933 new SparseArray<WindowState>();
934
935 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
936
937 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
938
939 private final RectF mTempRectF = new RectF();
940
941 private final Matrix mTempMatrix = new Matrix();
942
943 private final Point mTempPoint = new Point();
944
945 private final Rect mTempRect = new Rect();
946
947 private final Region mTempRegion = new Region();
948
949 private final Region mTempRegion1 = new Region();
950
951 private final Context mContext;
952
953 private final WindowManagerService mWindowManagerService;
954
955 private final Handler mHandler;
956
957 private final WindowsForAccessibilityCallback mCallback;
958
Svetoslavf7174e82014-06-12 11:29:35 -0700959 private final long mRecurringAccessibilityEventsIntervalMillis;
960
Svetoslav8e3feb12014-02-24 13:46:47 -0800961 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
962 WindowsForAccessibilityCallback callback) {
963 mContext = windowManagerService.mContext;
964 mWindowManagerService = windowManagerService;
965 mCallback = callback;
966 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700967 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
968 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800969 computeChangedWindows();
970 }
971
Svetoslav3a0d8782014-12-04 12:50:11 -0800972 public void performComputeChangedWindowsNotLocked() {
973 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
974 computeChangedWindows();
975 }
976
Svetoslavf7174e82014-06-12 11:29:35 -0700977 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800978 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -0700979 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
980 mRecurringAccessibilityEventsIntervalMillis);
981 }
982 }
983
Svetoslav8e3feb12014-02-24 13:46:47 -0800984 public void computeChangedWindows() {
985 if (DEBUG) {
986 Slog.i(LOG_TAG, "computeChangedWindows()");
987 }
988
Svetoslav3a0d8782014-12-04 12:50:11 -0800989 boolean windowsChanged = false;
990 List<WindowInfo> windows = new ArrayList<WindowInfo>();
991
Svetoslav8e3feb12014-02-24 13:46:47 -0800992 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700993 // Do not send the windows if there is no current focus as
994 // the window manager is still looking for where to put it.
995 // We will do the work when we get a focus change callback.
996 if (mWindowManagerService.mCurrentFocus == null) {
997 return;
998 }
999
Svetoslav8e3feb12014-02-24 13:46:47 -08001000 WindowManager windowManager = (WindowManager)
1001 mContext.getSystemService(Context.WINDOW_SERVICE);
1002 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1003 final int screenWidth = mTempPoint.x;
1004 final int screenHeight = mTempPoint.y;
1005
1006 Region unaccountedSpace = mTempRegion;
1007 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1008
1009 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1010 populateVisibleWindowsOnScreenLocked(visibleWindows);
1011
Svetoslav8e3feb12014-02-24 13:46:47 -08001012 Set<IBinder> addedWindows = mTempBinderSet;
1013 addedWindows.clear();
1014
Svetoslavf7174e82014-06-12 11:29:35 -07001015 boolean focusedWindowAdded = false;
1016
Svetoslav8e3feb12014-02-24 13:46:47 -08001017 final int visibleWindowCount = visibleWindows.size();
1018 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001019 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001020 final int flags = windowState.mAttrs.flags;
1021
Svetoslav3a5c7212014-10-14 09:54:26 -07001022 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001023 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001024 continue;
1025 }
1026
Alan Viverette9538eea2014-11-13 14:49:20 -08001027 // Compute the bounds in the screen.
1028 final Rect boundsInScreen = mTempRect;
1029 computeWindowBoundsInScreen(windowState, boundsInScreen);
1030
Svetoslav8e3feb12014-02-24 13:46:47 -08001031 // If the window is completely covered by other windows - ignore.
1032 if (unaccountedSpace.quickReject(boundsInScreen)) {
1033 continue;
1034 }
1035
1036 // Add windows of certain types not covered by modal windows.
1037 if (isReportedWindowType(windowState.mAttrs.type)) {
1038 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001039 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001040 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001041 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001042 if (windowState.isFocused()) {
1043 focusedWindowAdded = true;
1044 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001045 }
1046
Alan Viveretted0c73f42014-11-18 10:25:04 -08001047 // Account for the space this window takes if the window
1048 // is not an accessibility overlay which does not change
1049 // the reported windows.
1050 if (windowState.mAttrs.type !=
1051 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1052 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1053 Region.Op.REVERSE_DIFFERENCE);
1054 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001055
1056 // We figured out what is touchable for the entire screen - done.
1057 if (unaccountedSpace.isEmpty()) {
1058 break;
1059 }
1060
1061 // If a window is modal, no other below can be touched - done.
1062 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1063 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
1064 break;
1065 }
1066 }
1067
Svetoslavf7174e82014-06-12 11:29:35 -07001068 // Always report the focused window.
1069 if (!focusedWindowAdded) {
1070 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1071 WindowState windowState = visibleWindows.valueAt(i);
1072 if (windowState.isFocused()) {
1073 // Compute the bounds in the screen.
1074 Rect boundsInScreen = mTempRect;
1075 computeWindowBoundsInScreen(windowState, boundsInScreen);
1076
1077 // Add the window to the ones to be reported.
1078 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1079 boundsInScreen);
1080 addedWindows.add(window.token);
1081 windows.add(window);
1082 break;
1083 }
1084 }
1085 }
1086
Svetoslav8e3feb12014-02-24 13:46:47 -08001087 // Remove child/parent references to windows that were not added.
1088 final int windowCount = windows.size();
1089 for (int i = 0; i < windowCount; i++) {
1090 WindowInfo window = windows.get(i);
1091 if (!addedWindows.contains(window.parentToken)) {
1092 window.parentToken = null;
1093 }
1094 if (window.childTokens != null) {
1095 final int childTokenCount = window.childTokens.size();
1096 for (int j = childTokenCount - 1; j >= 0; j--) {
1097 if (!addedWindows.contains(window.childTokens.get(j))) {
1098 window.childTokens.remove(j);
1099 }
1100 }
1101 // Leave the child token list if empty.
1102 }
1103 }
1104
1105 visibleWindows.clear();
1106 addedWindows.clear();
1107
1108 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001109 if (mOldWindows.size() != windows.size()) {
1110 // Different size means something changed.
1111 windowsChanged = true;
1112 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1113 // Since we always traverse windows from high to low layer
1114 // the old and new windows at the same index should be the
1115 // same, otherwise something changed.
1116 for (int i = 0; i < windowCount; i++) {
1117 WindowInfo oldWindow = mOldWindows.get(i);
1118 WindowInfo newWindow = windows.get(i);
1119 // We do not care for layer changes given the window
1120 // order does not change. This brings no new information
1121 // to the clients.
1122 if (windowChangedNoLayer(oldWindow, newWindow)) {
1123 windowsChanged = true;
1124 break;
1125 }
1126 }
1127 }
1128
1129 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001130 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001131 }
1132 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001133
1134 // Now we do not hold the lock, so send the windows over.
1135 if (windowsChanged) {
1136 if (DEBUG) {
1137 Log.i(LOG_TAG, "Windows changed:" + windows);
1138 }
1139 mCallback.onWindowsForAccessibilityChanged(windows);
1140 } else {
1141 if (DEBUG) {
1142 Log.i(LOG_TAG, "No windows changed.");
1143 }
1144 }
1145
1146 // Recycle the windows as we do not need them.
1147 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001148 }
1149
Svetoslavf7174e82014-06-12 11:29:35 -07001150 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1151 // Get the touchable frame.
1152 Region touchableRegion = mTempRegion1;
1153 windowState.getTouchableRegion(touchableRegion);
1154 Rect touchableFrame = mTempRect;
1155 touchableRegion.getBounds(touchableFrame);
1156
1157 // Move to origin as all transforms are captured by the matrix.
1158 RectF windowFrame = mTempRectF;
1159 windowFrame.set(touchableFrame);
1160 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1161
1162 // Map the frame to get what appears on the screen.
1163 Matrix matrix = mTempMatrix;
1164 populateTransformationMatrixLocked(windowState, matrix);
1165 matrix.mapRect(windowFrame);
1166
1167 // Got the bounds.
1168 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1169 (int) windowFrame.right, (int) windowFrame.bottom);
1170 }
1171
1172 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1173 Rect boundsInScreen) {
1174 WindowInfo window = WindowInfo.obtain();
1175 window.type = windowState.mAttrs.type;
1176 window.layer = windowState.mLayer;
1177 window.token = windowState.mClient.asBinder();
1178
1179 WindowState attachedWindow = windowState.mAttachedWindow;
1180 if (attachedWindow != null) {
1181 window.parentToken = attachedWindow.mClient.asBinder();
1182 }
1183
1184 window.focused = windowState.isFocused();
1185 window.boundsInScreen.set(boundsInScreen);
1186
1187 final int childCount = windowState.mChildWindows.size();
1188 if (childCount > 0) {
1189 if (window.childTokens == null) {
1190 window.childTokens = new ArrayList<IBinder>();
1191 }
1192 for (int j = 0; j < childCount; j++) {
1193 WindowState child = windowState.mChildWindows.get(j);
1194 window.childTokens.add(child.mClient.asBinder());
1195 }
1196 }
1197
1198 return window;
1199 }
1200
Svetoslav8e3feb12014-02-24 13:46:47 -08001201 private void cacheWindows(List<WindowInfo> windows) {
1202 final int oldWindowCount = mOldWindows.size();
1203 for (int i = oldWindowCount - 1; i >= 0; i--) {
1204 mOldWindows.remove(i).recycle();
1205 }
1206 final int newWindowCount = windows.size();
1207 for (int i = 0; i < newWindowCount; i++) {
1208 WindowInfo newWindow = windows.get(i);
1209 mOldWindows.add(WindowInfo.obtain(newWindow));
1210 }
1211 }
1212
1213 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1214 if (oldWindow == newWindow) {
1215 return false;
1216 }
Svetoslavf7174e82014-06-12 11:29:35 -07001217 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001218 return true;
1219 }
Svetoslavf7174e82014-06-12 11:29:35 -07001220 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001221 return true;
1222 }
1223 if (oldWindow.type != newWindow.type) {
1224 return true;
1225 }
1226 if (oldWindow.focused != newWindow.focused) {
1227 return true;
1228 }
1229 if (oldWindow.token == null) {
1230 if (newWindow.token != null) {
1231 return true;
1232 }
1233 } else if (!oldWindow.token.equals(newWindow.token)) {
1234 return true;
1235 }
1236 if (oldWindow.parentToken == null) {
1237 if (newWindow.parentToken != null) {
1238 return true;
1239 }
1240 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1241 return true;
1242 }
1243 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1244 return true;
1245 }
1246 if (oldWindow.childTokens != null && newWindow.childTokens != null
1247 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1248 return true;
1249 }
1250 return false;
1251 }
1252
Svetoslav3a0d8782014-12-04 12:50:11 -08001253 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001254 final int windowCount = windows.size();
1255 for (int i = windowCount - 1; i >= 0; i--) {
1256 windows.remove(i).recycle();
1257 }
1258 }
1259
1260 private static boolean isReportedWindowType(int windowType) {
1261 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1262 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1263 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1264 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1265 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001266 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001267 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Svetoslav8e3feb12014-02-24 13:46:47 -08001268 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1269 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1270 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1271 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1272 }
1273
1274 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1275 DisplayContent displayContent = mWindowManagerService
1276 .getDefaultDisplayContentLocked();
1277 WindowList windowList = displayContent.getWindowList();
1278 final int windowCount = windowList.size();
1279 for (int i = 0; i < windowCount; i++) {
1280 WindowState windowState = windowList.get(i);
1281 if (windowState.isVisibleLw()) {
1282 outWindows.put(windowState.mLayer, windowState);
1283 }
1284 }
1285 }
1286
1287 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001288 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001289
1290 public MyHandler(Looper looper) {
1291 super(looper, null, false);
1292 }
1293
1294 @Override
1295 @SuppressWarnings("unchecked")
1296 public void handleMessage(Message message) {
1297 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001298 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1299 computeChangedWindows();
1300 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001301 }
1302 }
1303 }
1304 }
1305}