blob: 08754f9942a28b900040c23d87dabfef4a110070 [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;
209 sTempFloats[Matrix.MTRANS_X] = windowState.mShownFrame.left;
210 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownFrame.top;
211 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:
342 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
343 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
344 case WindowManager.LayoutParams.TYPE_PHONE:
345 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
346 case WindowManager.LayoutParams.TYPE_TOAST:
347 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
348 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
349 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
350 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
351 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
352 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Adrian Roos9a645132014-10-08 02:59:56 +0200353 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800354 Rect magnifiedRegionBounds = mTempRect2;
355 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
356 magnifiedRegionBounds);
357 Rect touchableRegionBounds = mTempRect1;
358 windowState.getTouchableRegion(mTempRegion1);
359 mTempRegion1.getBounds(touchableRegionBounds);
360 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
361 mCallbacks.onRectangleOnScreenRequested(
362 touchableRegionBounds.left,
363 touchableRegionBounds.top,
364 touchableRegionBounds.right,
365 touchableRegionBounds.bottom);
366 }
367 } break;
368 } break;
369 }
370 }
371 }
372
373 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
374 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
375 if (spec != null && !spec.isNop()) {
376 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
377 final int windowType = windowState.mAttrs.type;
378 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
379 && !policy.canMagnifyWindow(windowType)) {
380 return null;
381 }
382 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
383 return null;
384 }
385 }
386 return spec;
387 }
388
389 public void destroyLocked() {
390 mMagnifedViewport.destroyWindow();
391 }
392
393 /** NOTE: This has to be called within a surface transaction. */
394 public void drawMagnifiedRegionBorderIfNeededLocked() {
395 mMagnifedViewport.drawWindowIfNeededLocked();
396 }
397
398 private final class MagnifiedViewport {
399
400 private static final int DEFAUTLT_BORDER_WIDTH_DIP = 5;
401
402 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();
413
414 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
415
416 private final WindowManager mWindowManager;
417
Svetoslav7505e332014-08-22 12:14:28 -0700418 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800419 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700420 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800421
422 private final ViewportWindow mWindow;
423
424 private boolean mFullRedrawNeeded;
425
426 public MagnifiedViewport() {
427 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Svetoslav7505e332014-08-22 12:14:28 -0700428 mBorderWidth = TypedValue.applyDimension(
Svetoslav8e3feb12014-02-24 13:46:47 -0800429 TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP,
430 mContext.getResources().getDisplayMetrics());
Svetoslav7505e332014-08-22 12:14:28 -0700431 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
432 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800433 mWindow = new ViewportWindow(mContext);
434 recomputeBoundsLocked();
435 }
436
437 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
438 if (spec != null) {
439 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
440 } else {
441 mMagnificationSpec.clear();
442 }
443 // If this message is pending we are in a rotation animation and do not want
444 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700445 if (!mHandler.hasMessages(
446 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800447 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
448 }
449 }
450
451 public void recomputeBoundsLocked() {
452 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
453 final int screenWidth = mTempPoint.x;
454 final int screenHeight = mTempPoint.y;
455
456 Region magnifiedBounds = mMagnifiedBounds;
457 magnifiedBounds.set(0, 0, 0, 0);
458
459 Region availableBounds = mTempRegion1;
460 availableBounds.set(0, 0, screenWidth, screenHeight);
461
462 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700463 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800464
465 SparseArray<WindowState> visibleWindows = mTempWindowStates;
466 visibleWindows.clear();
467 populateWindowsOnScreenLocked(visibleWindows);
468
469 final int visibleWindowCount = visibleWindows.size();
470 for (int i = visibleWindowCount - 1; i >= 0; i--) {
471 WindowState windowState = visibleWindows.valueAt(i);
472 if (windowState.mAttrs.type == WindowManager
473 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
474 continue;
475 }
476
477 Region windowBounds = mTempRegion2;
478 Matrix matrix = mTempMatrix;
479 populateTransformationMatrixLocked(windowState, matrix);
480 RectF windowFrame = mTempRectF;
481
482 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
483 windowFrame.set(windowState.mFrame);
484 windowFrame.offset(-windowFrame.left, -windowFrame.top);
485 matrix.mapRect(windowFrame);
486 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
487 (int) windowFrame.right, (int) windowFrame.bottom);
488 magnifiedBounds.op(windowBounds, Region.Op.UNION);
489 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
490 } else {
491 Region touchableRegion = mTempRegion3;
492 windowState.getTouchableRegion(touchableRegion);
493 Rect touchableFrame = mTempRect1;
494 touchableRegion.getBounds(touchableFrame);
495 windowFrame.set(touchableFrame);
496 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
497 matrix.mapRect(windowFrame);
498 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
499 (int) windowFrame.right, (int) windowFrame.bottom);
500 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
501 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
502 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
503 }
504
505 Region accountedBounds = mTempRegion2;
506 accountedBounds.set(magnifiedBounds);
507 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
508 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
509
510 if (accountedBounds.isRect()) {
511 Rect accountedFrame = mTempRect1;
512 accountedBounds.getBounds(accountedFrame);
513 if (accountedFrame.width() == screenWidth
514 && accountedFrame.height() == screenHeight) {
515 break;
516 }
517 }
518 }
519
520 visibleWindows.clear();
521
Svetoslav7505e332014-08-22 12:14:28 -0700522 magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
523 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800524 Region.Op.INTERSECT);
525
526 if (!mOldMagnifiedBounds.equals(magnifiedBounds)) {
527 Region bounds = Region.obtain();
528 bounds.set(magnifiedBounds);
529 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED,
530 bounds).sendToTarget();
531
532 mWindow.setBounds(magnifiedBounds);
533 Rect dirtyRect = mTempRect1;
534 if (mFullRedrawNeeded) {
535 mFullRedrawNeeded = false;
Svetoslav7505e332014-08-22 12:14:28 -0700536 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
537 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset);
Svetoslav8e3feb12014-02-24 13:46:47 -0800538 mWindow.invalidate(dirtyRect);
539 } else {
540 Region dirtyRegion = mTempRegion3;
541 dirtyRegion.set(magnifiedBounds);
542 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
543 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
544 dirtyRegion.getBounds(dirtyRect);
545 mWindow.invalidate(dirtyRect);
546 }
547
548 mOldMagnifiedBounds.set(magnifiedBounds);
549 }
550 }
551
552 public void onRotationChangedLocked() {
553 // If we are magnifying, hide the magnified border window immediately so
554 // the user does not see strange artifacts during rotation. The screenshot
555 // used for rotation has already the border. After the rotation is complete
556 // we will show the border.
557 if (isMagnifyingLocked()) {
558 setMagnifiedRegionBorderShownLocked(false, false);
559 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700560 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800561 Message message = mHandler.obtainMessage(
562 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
563 mHandler.sendMessageDelayed(message, delay);
564 }
565 recomputeBoundsLocked();
566 mWindow.updateSize();
567 }
568
569 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
570 if (shown) {
571 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700572 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800573 }
574 mWindow.setShown(shown, animate);
575 }
576
577 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
578 MagnificationSpec spec = mMagnificationSpec;
579 mMagnifiedBounds.getBounds(rect);
580 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
581 rect.scale(1.0f / spec.scale);
582 }
583
584 public boolean isMagnifyingLocked() {
585 return mMagnificationSpec.scale > 1.0f;
586 }
587
588 public MagnificationSpec getMagnificationSpecLocked() {
589 return mMagnificationSpec;
590 }
591
592 /** NOTE: This has to be called within a surface transaction. */
593 public void drawWindowIfNeededLocked() {
594 recomputeBoundsLocked();
595 mWindow.drawIfNeeded();
596 }
597
598 public void destroyWindow() {
599 mWindow.releaseSurface();
600 }
601
602 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
603 DisplayContent displayContent = mWindowManagerService
604 .getDefaultDisplayContentLocked();
605 WindowList windowList = displayContent.getWindowList();
606 final int windowCount = windowList.size();
607 for (int i = 0; i < windowCount; i++) {
608 WindowState windowState = windowList.get(i);
609 if ((windowState.isOnScreen() || windowState.mAttrs.type == WindowManager
610 .LayoutParams.TYPE_UNIVERSE_BACKGROUND)
611 && !windowState.mWinAnimator.mEnterAnimationPending) {
612 outWindows.put(windowState.mLayer, windowState);
613 }
614 }
615 }
616
617 private final class ViewportWindow {
618 private static final String SURFACE_TITLE = "Magnification Overlay";
619
Svetoslav8e3feb12014-02-24 13:46:47 -0800620 private final Region mBounds = new Region();
621 private final Rect mDirtyRect = new Rect();
622 private final Paint mPaint = new Paint();
623
Svetoslav8e3feb12014-02-24 13:46:47 -0800624 private final SurfaceControl mSurfaceControl;
625 private final Surface mSurface = new Surface();
626
Svet Ganovb21df802014-09-01 19:06:33 -0700627 private final AnimationController mAnimationController;
628
Svetoslav8e3feb12014-02-24 13:46:47 -0800629 private boolean mShown;
630 private int mAlpha;
631
632 private boolean mInvalidated;
633
634 public ViewportWindow(Context context) {
635 SurfaceControl surfaceControl = null;
636 try {
637 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
638 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
639 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
640 SurfaceControl.HIDDEN);
641 } catch (OutOfResourcesException oore) {
642 /* ignore */
643 }
644 mSurfaceControl = surfaceControl;
645 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
646 .getLayerStack());
647 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
648 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
649 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
650 mSurfaceControl.setPosition(0, 0);
651 mSurface.copyFrom(mSurfaceControl);
652
Svet Ganovb21df802014-09-01 19:06:33 -0700653 mAnimationController = new AnimationController(context,
654 mWindowManagerService.mH.getLooper());
655
Svetoslav8e3feb12014-02-24 13:46:47 -0800656 TypedValue typedValue = new TypedValue();
657 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
658 typedValue, true);
659 final int borderColor = context.getResources().getColor(typedValue.resourceId);
660
661 mPaint.setStyle(Paint.Style.STROKE);
662 mPaint.setStrokeWidth(mBorderWidth);
663 mPaint.setColor(borderColor);
664
Svetoslav8e3feb12014-02-24 13:46:47 -0800665 mInvalidated = true;
666 }
667
668 public void setShown(boolean shown, boolean animate) {
669 synchronized (mWindowManagerService.mWindowMap) {
670 if (mShown == shown) {
671 return;
672 }
673 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700674 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800675 if (DEBUG_VIEWPORT_WINDOW) {
676 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
677 }
678 }
679 }
680
681 @SuppressWarnings("unused")
682 // Called reflectively from an animator.
683 public int getAlpha() {
684 synchronized (mWindowManagerService.mWindowMap) {
685 return mAlpha;
686 }
687 }
688
689 public void setAlpha(int alpha) {
690 synchronized (mWindowManagerService.mWindowMap) {
691 if (mAlpha == alpha) {
692 return;
693 }
694 mAlpha = alpha;
695 invalidate(null);
696 if (DEBUG_VIEWPORT_WINDOW) {
697 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
698 }
699 }
700 }
701
702 public void setBounds(Region bounds) {
703 synchronized (mWindowManagerService.mWindowMap) {
704 if (mBounds.equals(bounds)) {
705 return;
706 }
707 mBounds.set(bounds);
708 invalidate(mDirtyRect);
709 if (DEBUG_VIEWPORT_WINDOW) {
710 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
711 }
712 }
713 }
714
715 public void updateSize() {
716 synchronized (mWindowManagerService.mWindowMap) {
717 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
718 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
719 invalidate(mDirtyRect);
720 }
721 }
722
723 public void invalidate(Rect dirtyRect) {
724 if (dirtyRect != null) {
725 mDirtyRect.set(dirtyRect);
726 } else {
727 mDirtyRect.setEmpty();
728 }
729 mInvalidated = true;
730 mWindowManagerService.scheduleAnimationLocked();
731 }
732
733 /** NOTE: This has to be called within a surface transaction. */
734 public void drawIfNeeded() {
735 synchronized (mWindowManagerService.mWindowMap) {
736 if (!mInvalidated) {
737 return;
738 }
739 mInvalidated = false;
740 Canvas canvas = null;
741 try {
742 // Empty dirty rectangle means unspecified.
743 if (mDirtyRect.isEmpty()) {
744 mBounds.getBounds(mDirtyRect);
745 }
746 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
747 canvas = mSurface.lockCanvas(mDirtyRect);
748 if (DEBUG_VIEWPORT_WINDOW) {
749 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
750 }
751 } catch (IllegalArgumentException iae) {
752 /* ignore */
753 } catch (Surface.OutOfResourcesException oore) {
754 /* ignore */
755 }
756 if (canvas == null) {
757 return;
758 }
759 if (DEBUG_VIEWPORT_WINDOW) {
760 Slog.i(LOG_TAG, "Bounds: " + mBounds);
761 }
762 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
763 mPaint.setAlpha(mAlpha);
764 Path path = mBounds.getBoundaryPath();
765 canvas.drawPath(path, mPaint);
766
767 mSurface.unlockCanvasAndPost(canvas);
768
769 if (mAlpha > 0) {
770 mSurfaceControl.show();
771 } else {
772 mSurfaceControl.hide();
773 }
774 }
775 }
776
777 public void releaseSurface() {
778 mSurfaceControl.release();
779 mSurface.release();
780 }
Svet Ganovb21df802014-09-01 19:06:33 -0700781
782 private final class AnimationController extends Handler {
783 private static final String PROPERTY_NAME_ALPHA = "alpha";
784
785 private static final int MIN_ALPHA = 0;
786 private static final int MAX_ALPHA = 255;
787
788 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
789
790 private final ValueAnimator mShowHideFrameAnimator;
791
792 public AnimationController(Context context, Looper looper) {
793 super(looper);
794 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
795 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
796
797 Interpolator interpolator = new DecelerateInterpolator(2.5f);
798 final long longAnimationDuration = context.getResources().getInteger(
799 com.android.internal.R.integer.config_longAnimTime);
800
801 mShowHideFrameAnimator.setInterpolator(interpolator);
802 mShowHideFrameAnimator.setDuration(longAnimationDuration);
803 }
804
805 public void onFrameShownStateChanged(boolean shown, boolean animate) {
806 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
807 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
808 }
809
810 @Override
811 public void handleMessage(Message message) {
812 switch (message.what) {
813 case MSG_FRAME_SHOWN_STATE_CHANGED: {
814 final boolean shown = message.arg1 == 1;
815 final boolean animate = message.arg2 == 1;
816
817 if (animate) {
818 if (mShowHideFrameAnimator.isRunning()) {
819 mShowHideFrameAnimator.reverse();
820 } else {
821 if (shown) {
822 mShowHideFrameAnimator.start();
823 } else {
824 mShowHideFrameAnimator.reverse();
825 }
826 }
827 } else {
828 mShowHideFrameAnimator.cancel();
829 if (shown) {
830 setAlpha(MAX_ALPHA);
831 } else {
832 setAlpha(MIN_ALPHA);
833 }
834 }
835 } break;
836 }
837 }
838 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800839 }
840 }
841
842 private class MyHandler extends Handler {
843 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
844 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
845 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
846 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
847 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
848
849 public MyHandler(Looper looper) {
850 super(looper);
851 }
852
853 @Override
854 public void handleMessage(Message message) {
855 switch (message.what) {
856 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
857 Region bounds = (Region) message.obj;
858 mCallbacks.onMagnifedBoundsChanged(bounds);
859 bounds.recycle();
860 } break;
861
862 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
863 SomeArgs args = (SomeArgs) message.obj;
864 final int left = args.argi1;
865 final int top = args.argi2;
866 final int right = args.argi3;
867 final int bottom = args.argi4;
868 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
869 args.recycle();
870 } break;
871
872 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
873 mCallbacks.onUserContextChanged();
874 } break;
875
876 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
877 final int rotation = message.arg1;
878 mCallbacks.onRotationChanged(rotation);
879 } break;
880
881 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
882 synchronized (mWindowManagerService.mWindowMap) {
883 if (mMagnifedViewport.isMagnifyingLocked()) {
884 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
885 mWindowManagerService.scheduleAnimationLocked();
886 }
887 }
888 } break;
889 }
890 }
891 }
892 }
893
894 /**
895 * This class encapsulates the functionality related to computing the windows
896 * reported for accessibility purposes. These windows are all windows a sighted
897 * user can see on the screen.
898 */
899 private static final class WindowsForAccessibilityObserver {
900 private static final String LOG_TAG = "WindowsForAccessibilityObserver";
901
902 private static final boolean DEBUG = false;
903
904 private final SparseArray<WindowState> mTempWindowStates =
905 new SparseArray<WindowState>();
906
907 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
908
909 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
910
911 private final RectF mTempRectF = new RectF();
912
913 private final Matrix mTempMatrix = new Matrix();
914
915 private final Point mTempPoint = new Point();
916
917 private final Rect mTempRect = new Rect();
918
919 private final Region mTempRegion = new Region();
920
921 private final Region mTempRegion1 = new Region();
922
923 private final Context mContext;
924
925 private final WindowManagerService mWindowManagerService;
926
927 private final Handler mHandler;
928
929 private final WindowsForAccessibilityCallback mCallback;
930
Svetoslavf7174e82014-06-12 11:29:35 -0700931 private final long mRecurringAccessibilityEventsIntervalMillis;
932
Svetoslav8e3feb12014-02-24 13:46:47 -0800933 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
934 WindowsForAccessibilityCallback callback) {
935 mContext = windowManagerService.mContext;
936 mWindowManagerService = windowManagerService;
937 mCallback = callback;
938 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700939 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
940 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800941 computeChangedWindows();
942 }
943
Svetoslav3a0d8782014-12-04 12:50:11 -0800944 public void performComputeChangedWindowsNotLocked() {
945 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
946 computeChangedWindows();
947 }
948
Svetoslavf7174e82014-06-12 11:29:35 -0700949 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800950 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -0700951 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
952 mRecurringAccessibilityEventsIntervalMillis);
953 }
954 }
955
Svetoslav8e3feb12014-02-24 13:46:47 -0800956 public void computeChangedWindows() {
957 if (DEBUG) {
958 Slog.i(LOG_TAG, "computeChangedWindows()");
959 }
960
Svetoslav3a0d8782014-12-04 12:50:11 -0800961 boolean windowsChanged = false;
962 List<WindowInfo> windows = new ArrayList<WindowInfo>();
963
Svetoslav8e3feb12014-02-24 13:46:47 -0800964 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700965 // Do not send the windows if there is no current focus as
966 // the window manager is still looking for where to put it.
967 // We will do the work when we get a focus change callback.
968 if (mWindowManagerService.mCurrentFocus == null) {
969 return;
970 }
971
Svetoslav8e3feb12014-02-24 13:46:47 -0800972 WindowManager windowManager = (WindowManager)
973 mContext.getSystemService(Context.WINDOW_SERVICE);
974 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
975 final int screenWidth = mTempPoint.x;
976 final int screenHeight = mTempPoint.y;
977
978 Region unaccountedSpace = mTempRegion;
979 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
980
981 SparseArray<WindowState> visibleWindows = mTempWindowStates;
982 populateVisibleWindowsOnScreenLocked(visibleWindows);
983
Svetoslav8e3feb12014-02-24 13:46:47 -0800984 Set<IBinder> addedWindows = mTempBinderSet;
985 addedWindows.clear();
986
Svetoslavf7174e82014-06-12 11:29:35 -0700987 boolean focusedWindowAdded = false;
988
Svetoslav8e3feb12014-02-24 13:46:47 -0800989 final int visibleWindowCount = visibleWindows.size();
990 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -0800991 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -0800992 final int flags = windowState.mAttrs.flags;
993
Svetoslav3a5c7212014-10-14 09:54:26 -0700994 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -0700995 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800996 continue;
997 }
998
Alan Viverette9538eea2014-11-13 14:49:20 -0800999 // Compute the bounds in the screen.
1000 final Rect boundsInScreen = mTempRect;
1001 computeWindowBoundsInScreen(windowState, boundsInScreen);
1002
Svetoslav8e3feb12014-02-24 13:46:47 -08001003 // If the window is completely covered by other windows - ignore.
1004 if (unaccountedSpace.quickReject(boundsInScreen)) {
1005 continue;
1006 }
1007
1008 // Add windows of certain types not covered by modal windows.
1009 if (isReportedWindowType(windowState.mAttrs.type)) {
1010 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001011 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001012 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001013 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001014 if (windowState.isFocused()) {
1015 focusedWindowAdded = true;
1016 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001017 }
1018
Alan Viveretted0c73f42014-11-18 10:25:04 -08001019 // Account for the space this window takes if the window
1020 // is not an accessibility overlay which does not change
1021 // the reported windows.
1022 if (windowState.mAttrs.type !=
1023 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1024 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1025 Region.Op.REVERSE_DIFFERENCE);
1026 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001027
1028 // We figured out what is touchable for the entire screen - done.
1029 if (unaccountedSpace.isEmpty()) {
1030 break;
1031 }
1032
1033 // If a window is modal, no other below can be touched - done.
1034 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1035 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
1036 break;
1037 }
1038 }
1039
Svetoslavf7174e82014-06-12 11:29:35 -07001040 // Always report the focused window.
1041 if (!focusedWindowAdded) {
1042 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1043 WindowState windowState = visibleWindows.valueAt(i);
1044 if (windowState.isFocused()) {
1045 // Compute the bounds in the screen.
1046 Rect boundsInScreen = mTempRect;
1047 computeWindowBoundsInScreen(windowState, boundsInScreen);
1048
1049 // Add the window to the ones to be reported.
1050 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1051 boundsInScreen);
1052 addedWindows.add(window.token);
1053 windows.add(window);
1054 break;
1055 }
1056 }
1057 }
1058
Svetoslav8e3feb12014-02-24 13:46:47 -08001059 // Remove child/parent references to windows that were not added.
1060 final int windowCount = windows.size();
1061 for (int i = 0; i < windowCount; i++) {
1062 WindowInfo window = windows.get(i);
1063 if (!addedWindows.contains(window.parentToken)) {
1064 window.parentToken = null;
1065 }
1066 if (window.childTokens != null) {
1067 final int childTokenCount = window.childTokens.size();
1068 for (int j = childTokenCount - 1; j >= 0; j--) {
1069 if (!addedWindows.contains(window.childTokens.get(j))) {
1070 window.childTokens.remove(j);
1071 }
1072 }
1073 // Leave the child token list if empty.
1074 }
1075 }
1076
1077 visibleWindows.clear();
1078 addedWindows.clear();
1079
1080 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001081 if (mOldWindows.size() != windows.size()) {
1082 // Different size means something changed.
1083 windowsChanged = true;
1084 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1085 // Since we always traverse windows from high to low layer
1086 // the old and new windows at the same index should be the
1087 // same, otherwise something changed.
1088 for (int i = 0; i < windowCount; i++) {
1089 WindowInfo oldWindow = mOldWindows.get(i);
1090 WindowInfo newWindow = windows.get(i);
1091 // We do not care for layer changes given the window
1092 // order does not change. This brings no new information
1093 // to the clients.
1094 if (windowChangedNoLayer(oldWindow, newWindow)) {
1095 windowsChanged = true;
1096 break;
1097 }
1098 }
1099 }
1100
1101 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001102 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001103 }
1104 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001105
1106 // Now we do not hold the lock, so send the windows over.
1107 if (windowsChanged) {
1108 if (DEBUG) {
1109 Log.i(LOG_TAG, "Windows changed:" + windows);
1110 }
1111 mCallback.onWindowsForAccessibilityChanged(windows);
1112 } else {
1113 if (DEBUG) {
1114 Log.i(LOG_TAG, "No windows changed.");
1115 }
1116 }
1117
1118 // Recycle the windows as we do not need them.
1119 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001120 }
1121
Svetoslavf7174e82014-06-12 11:29:35 -07001122 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1123 // Get the touchable frame.
1124 Region touchableRegion = mTempRegion1;
1125 windowState.getTouchableRegion(touchableRegion);
1126 Rect touchableFrame = mTempRect;
1127 touchableRegion.getBounds(touchableFrame);
1128
1129 // Move to origin as all transforms are captured by the matrix.
1130 RectF windowFrame = mTempRectF;
1131 windowFrame.set(touchableFrame);
1132 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1133
1134 // Map the frame to get what appears on the screen.
1135 Matrix matrix = mTempMatrix;
1136 populateTransformationMatrixLocked(windowState, matrix);
1137 matrix.mapRect(windowFrame);
1138
1139 // Got the bounds.
1140 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1141 (int) windowFrame.right, (int) windowFrame.bottom);
1142 }
1143
1144 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1145 Rect boundsInScreen) {
1146 WindowInfo window = WindowInfo.obtain();
1147 window.type = windowState.mAttrs.type;
1148 window.layer = windowState.mLayer;
1149 window.token = windowState.mClient.asBinder();
1150
1151 WindowState attachedWindow = windowState.mAttachedWindow;
1152 if (attachedWindow != null) {
1153 window.parentToken = attachedWindow.mClient.asBinder();
1154 }
1155
1156 window.focused = windowState.isFocused();
1157 window.boundsInScreen.set(boundsInScreen);
1158
1159 final int childCount = windowState.mChildWindows.size();
1160 if (childCount > 0) {
1161 if (window.childTokens == null) {
1162 window.childTokens = new ArrayList<IBinder>();
1163 }
1164 for (int j = 0; j < childCount; j++) {
1165 WindowState child = windowState.mChildWindows.get(j);
1166 window.childTokens.add(child.mClient.asBinder());
1167 }
1168 }
1169
1170 return window;
1171 }
1172
Svetoslav8e3feb12014-02-24 13:46:47 -08001173 private void cacheWindows(List<WindowInfo> windows) {
1174 final int oldWindowCount = mOldWindows.size();
1175 for (int i = oldWindowCount - 1; i >= 0; i--) {
1176 mOldWindows.remove(i).recycle();
1177 }
1178 final int newWindowCount = windows.size();
1179 for (int i = 0; i < newWindowCount; i++) {
1180 WindowInfo newWindow = windows.get(i);
1181 mOldWindows.add(WindowInfo.obtain(newWindow));
1182 }
1183 }
1184
1185 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1186 if (oldWindow == newWindow) {
1187 return false;
1188 }
Svetoslavf7174e82014-06-12 11:29:35 -07001189 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001190 return true;
1191 }
Svetoslavf7174e82014-06-12 11:29:35 -07001192 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001193 return true;
1194 }
1195 if (oldWindow.type != newWindow.type) {
1196 return true;
1197 }
1198 if (oldWindow.focused != newWindow.focused) {
1199 return true;
1200 }
1201 if (oldWindow.token == null) {
1202 if (newWindow.token != null) {
1203 return true;
1204 }
1205 } else if (!oldWindow.token.equals(newWindow.token)) {
1206 return true;
1207 }
1208 if (oldWindow.parentToken == null) {
1209 if (newWindow.parentToken != null) {
1210 return true;
1211 }
1212 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1213 return true;
1214 }
1215 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1216 return true;
1217 }
1218 if (oldWindow.childTokens != null && newWindow.childTokens != null
1219 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1220 return true;
1221 }
1222 return false;
1223 }
1224
Svetoslav3a0d8782014-12-04 12:50:11 -08001225 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001226 final int windowCount = windows.size();
1227 for (int i = windowCount - 1; i >= 0; i--) {
1228 windows.remove(i).recycle();
1229 }
1230 }
1231
1232 private static boolean isReportedWindowType(int windowType) {
1233 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1234 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1235 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1236 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1237 && windowType != WindowManager.LayoutParams.TYPE_DRAG
1238 && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
1239 && windowType != WindowManager.LayoutParams.TYPE_POINTER
1240 && windowType != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
1241 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1242 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1243 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1244 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1245 }
1246
1247 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1248 DisplayContent displayContent = mWindowManagerService
1249 .getDefaultDisplayContentLocked();
1250 WindowList windowList = displayContent.getWindowList();
1251 final int windowCount = windowList.size();
1252 for (int i = 0; i < windowCount; i++) {
1253 WindowState windowState = windowList.get(i);
1254 if (windowState.isVisibleLw()) {
1255 outWindows.put(windowState.mLayer, windowState);
1256 }
1257 }
1258 }
1259
1260 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001261 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001262
1263 public MyHandler(Looper looper) {
1264 super(looper, null, false);
1265 }
1266
1267 @Override
1268 @SuppressWarnings("unchecked")
1269 public void handleMessage(Message message) {
1270 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001271 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1272 computeChangedWindows();
1273 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001274 }
1275 }
1276 }
1277 }
1278}