blob: 6cb6b7690d660979eb31a325cbf30b6a1d525afd [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
162 public void onWindowFocusChangedLocked() {
163 // Not relevant for the display magnifier.
164
165 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700166 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800167 }
168 }
169
Svetoslav4604abc2014-06-10 18:59:30 -0700170
Svetoslavf7174e82014-06-12 11:29:35 -0700171 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700172 // Not relevant for the display magnifier.
173
174 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700175 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700176 }
177 }
178
Svetoslav8e3feb12014-02-24 13:46:47 -0800179 /** NOTE: This has to be called within a surface transaction. */
180 public void drawMagnifiedRegionBorderIfNeededLocked() {
181 if (mDisplayMagnifier != null) {
182 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
183 }
184 // Not relevant for the window observer.
185 }
186
187 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
188 if (mDisplayMagnifier != null) {
189 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
190 }
191 return null;
192 }
193
194 public boolean hasCallbacksLocked() {
195 return (mDisplayMagnifier != null
196 || mWindowsForAccessibilityObserver != null);
197 }
198
199 private static void populateTransformationMatrixLocked(WindowState windowState,
200 Matrix outMatrix) {
201 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
202 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
203 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
204 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
205 sTempFloats[Matrix.MTRANS_X] = windowState.mShownFrame.left;
206 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownFrame.top;
207 sTempFloats[Matrix.MPERSP_0] = 0;
208 sTempFloats[Matrix.MPERSP_1] = 0;
209 sTempFloats[Matrix.MPERSP_2] = 1;
210 outMatrix.setValues(sTempFloats);
211 }
212
213 /**
214 * This class encapsulates the functionality related to display magnification.
215 */
216 private static final class DisplayMagnifier {
217
218 private static final String LOG_TAG = "DisplayMagnifier";
219
220 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
221 private static final boolean DEBUG_ROTATION = false;
222 private static final boolean DEBUG_LAYERS = false;
223 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
224 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
225
226 private final Rect mTempRect1 = new Rect();
227 private final Rect mTempRect2 = new Rect();
228
229 private final Region mTempRegion1 = new Region();
230 private final Region mTempRegion2 = new Region();
231 private final Region mTempRegion3 = new Region();
232 private final Region mTempRegion4 = new Region();
233
234 private final Context mContext;
235 private final WindowManagerService mWindowManagerService;
236 private final MagnifiedViewport mMagnifedViewport;
237 private final Handler mHandler;
238
239 private final MagnificationCallbacks mCallbacks;
240
241 private final long mLongAnimationDuration;
242
243 public DisplayMagnifier(WindowManagerService windowManagerService,
244 MagnificationCallbacks callbacks) {
245 mContext = windowManagerService.mContext;
246 mWindowManagerService = windowManagerService;
247 mCallbacks = callbacks;
248 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
249 mMagnifedViewport = new MagnifiedViewport();
250 mLongAnimationDuration = mContext.getResources().getInteger(
251 com.android.internal.R.integer.config_longAnimTime);
252 }
253
254 public void setMagnificationSpecLocked(MagnificationSpec spec) {
255 mMagnifedViewport.updateMagnificationSpecLocked(spec);
256 mMagnifedViewport.recomputeBoundsLocked();
257 mWindowManagerService.scheduleAnimationLocked();
258 }
259
Svetoslavf7174e82014-06-12 11:29:35 -0700260 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800261 if (DEBUG_RECTANGLE_REQUESTED) {
262 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
263 }
264 if (!mMagnifedViewport.isMagnifyingLocked()) {
265 return;
266 }
267 Rect magnifiedRegionBounds = mTempRect2;
268 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
269 if (magnifiedRegionBounds.contains(rectangle)) {
270 return;
271 }
272 SomeArgs args = SomeArgs.obtain();
273 args.argi1 = rectangle.left;
274 args.argi2 = rectangle.top;
275 args.argi3 = rectangle.right;
276 args.argi4 = rectangle.bottom;
277 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
278 args).sendToTarget();
279 }
280
281 public void onWindowLayersChangedLocked() {
282 if (DEBUG_LAYERS) {
283 Slog.i(LOG_TAG, "Layers changed.");
284 }
285 mMagnifedViewport.recomputeBoundsLocked();
286 mWindowManagerService.scheduleAnimationLocked();
287 }
288
289 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
290 if (DEBUG_ROTATION) {
291 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
292 + " displayId: " + displayContent.getDisplayId());
293 }
294 mMagnifedViewport.onRotationChangedLocked();
295 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
296 }
297
298 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
299 if (DEBUG_WINDOW_TRANSITIONS) {
300 Slog.i(LOG_TAG, "Window transition: "
301 + AppTransition.appTransitionToString(transition)
302 + " displayId: " + windowState.getDisplayId());
303 }
304 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
305 if (magnifying) {
306 switch (transition) {
307 case AppTransition.TRANSIT_ACTIVITY_OPEN:
308 case AppTransition.TRANSIT_TASK_OPEN:
309 case AppTransition.TRANSIT_TASK_TO_FRONT:
310 case AppTransition.TRANSIT_WALLPAPER_OPEN:
311 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
312 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
313 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
314 }
315 }
316 }
317 }
318
319 public void onWindowTransitionLocked(WindowState windowState, int transition) {
320 if (DEBUG_WINDOW_TRANSITIONS) {
321 Slog.i(LOG_TAG, "Window transition: "
322 + AppTransition.appTransitionToString(transition)
323 + " displayId: " + windowState.getDisplayId());
324 }
325 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
326 final int type = windowState.mAttrs.type;
327 switch (transition) {
328 case WindowManagerPolicy.TRANSIT_ENTER:
329 case WindowManagerPolicy.TRANSIT_SHOW: {
330 if (!magnifying) {
331 break;
332 }
333 switch (type) {
334 case WindowManager.LayoutParams.TYPE_APPLICATION:
335 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
336 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
337 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
338 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
339 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
340 case WindowManager.LayoutParams.TYPE_PHONE:
341 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
342 case WindowManager.LayoutParams.TYPE_TOAST:
343 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
344 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
345 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
346 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
347 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
348 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
349 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
350 case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
351 Rect magnifiedRegionBounds = mTempRect2;
352 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
353 magnifiedRegionBounds);
354 Rect touchableRegionBounds = mTempRect1;
355 windowState.getTouchableRegion(mTempRegion1);
356 mTempRegion1.getBounds(touchableRegionBounds);
357 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
358 mCallbacks.onRectangleOnScreenRequested(
359 touchableRegionBounds.left,
360 touchableRegionBounds.top,
361 touchableRegionBounds.right,
362 touchableRegionBounds.bottom);
363 }
364 } break;
365 } break;
366 }
367 }
368 }
369
370 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
371 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
372 if (spec != null && !spec.isNop()) {
373 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
374 final int windowType = windowState.mAttrs.type;
375 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
376 && !policy.canMagnifyWindow(windowType)) {
377 return null;
378 }
379 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
380 return null;
381 }
382 }
383 return spec;
384 }
385
386 public void destroyLocked() {
387 mMagnifedViewport.destroyWindow();
388 }
389
390 /** NOTE: This has to be called within a surface transaction. */
391 public void drawMagnifiedRegionBorderIfNeededLocked() {
392 mMagnifedViewport.drawWindowIfNeededLocked();
393 }
394
395 private final class MagnifiedViewport {
396
397 private static final int DEFAUTLT_BORDER_WIDTH_DIP = 5;
398
399 private final SparseArray<WindowState> mTempWindowStates =
400 new SparseArray<WindowState>();
401
402 private final RectF mTempRectF = new RectF();
403
404 private final Point mTempPoint = new Point();
405
406 private final Matrix mTempMatrix = new Matrix();
407
408 private final Region mMagnifiedBounds = new Region();
409 private final Region mOldMagnifiedBounds = new Region();
410
411 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
412
413 private final WindowManager mWindowManager;
414
415 private final int mBorderWidth;
416 private final int mHalfBorderWidth;
417
418 private final ViewportWindow mWindow;
419
420 private boolean mFullRedrawNeeded;
421
422 public MagnifiedViewport() {
423 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
424 mBorderWidth = (int) TypedValue.applyDimension(
425 TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP,
426 mContext.getResources().getDisplayMetrics());
427 mHalfBorderWidth = (int) (mBorderWidth + 0.5) / 2;
428 mWindow = new ViewportWindow(mContext);
429 recomputeBoundsLocked();
430 }
431
432 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
433 if (spec != null) {
434 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
435 } else {
436 mMagnificationSpec.clear();
437 }
438 // If this message is pending we are in a rotation animation and do not want
439 // to show the border. We will do so when the pending message is handled.
440 if (!mHandler.hasMessages(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
441 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
442 }
443 }
444
445 public void recomputeBoundsLocked() {
446 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
447 final int screenWidth = mTempPoint.x;
448 final int screenHeight = mTempPoint.y;
449
450 Region magnifiedBounds = mMagnifiedBounds;
451 magnifiedBounds.set(0, 0, 0, 0);
452
453 Region availableBounds = mTempRegion1;
454 availableBounds.set(0, 0, screenWidth, screenHeight);
455
456 Region nonMagnifiedBounds = mTempRegion4;
457 nonMagnifiedBounds.set(0, 0, 0, 0);
458
459 SparseArray<WindowState> visibleWindows = mTempWindowStates;
460 visibleWindows.clear();
461 populateWindowsOnScreenLocked(visibleWindows);
462
463 final int visibleWindowCount = visibleWindows.size();
464 for (int i = visibleWindowCount - 1; i >= 0; i--) {
465 WindowState windowState = visibleWindows.valueAt(i);
466 if (windowState.mAttrs.type == WindowManager
467 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
468 continue;
469 }
470
471 Region windowBounds = mTempRegion2;
472 Matrix matrix = mTempMatrix;
473 populateTransformationMatrixLocked(windowState, matrix);
474 RectF windowFrame = mTempRectF;
475
476 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
477 windowFrame.set(windowState.mFrame);
478 windowFrame.offset(-windowFrame.left, -windowFrame.top);
479 matrix.mapRect(windowFrame);
480 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
481 (int) windowFrame.right, (int) windowFrame.bottom);
482 magnifiedBounds.op(windowBounds, Region.Op.UNION);
483 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
484 } else {
485 Region touchableRegion = mTempRegion3;
486 windowState.getTouchableRegion(touchableRegion);
487 Rect touchableFrame = mTempRect1;
488 touchableRegion.getBounds(touchableFrame);
489 windowFrame.set(touchableFrame);
490 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
491 matrix.mapRect(windowFrame);
492 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
493 (int) windowFrame.right, (int) windowFrame.bottom);
494 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
495 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
496 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
497 }
498
499 Region accountedBounds = mTempRegion2;
500 accountedBounds.set(magnifiedBounds);
501 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
502 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
503
504 if (accountedBounds.isRect()) {
505 Rect accountedFrame = mTempRect1;
506 accountedBounds.getBounds(accountedFrame);
507 if (accountedFrame.width() == screenWidth
508 && accountedFrame.height() == screenHeight) {
509 break;
510 }
511 }
512 }
513
514 visibleWindows.clear();
515
516 magnifiedBounds.op(mHalfBorderWidth, mHalfBorderWidth,
517 screenWidth - mHalfBorderWidth, screenHeight - mHalfBorderWidth,
518 Region.Op.INTERSECT);
519
520 if (!mOldMagnifiedBounds.equals(magnifiedBounds)) {
521 Region bounds = Region.obtain();
522 bounds.set(magnifiedBounds);
523 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED,
524 bounds).sendToTarget();
525
526 mWindow.setBounds(magnifiedBounds);
527 Rect dirtyRect = mTempRect1;
528 if (mFullRedrawNeeded) {
529 mFullRedrawNeeded = false;
530 dirtyRect.set(mHalfBorderWidth, mHalfBorderWidth,
531 screenWidth - mHalfBorderWidth, screenHeight - mHalfBorderWidth);
532 mWindow.invalidate(dirtyRect);
533 } else {
534 Region dirtyRegion = mTempRegion3;
535 dirtyRegion.set(magnifiedBounds);
536 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
537 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
538 dirtyRegion.getBounds(dirtyRect);
539 mWindow.invalidate(dirtyRect);
540 }
541
542 mOldMagnifiedBounds.set(magnifiedBounds);
543 }
544 }
545
546 public void onRotationChangedLocked() {
547 // If we are magnifying, hide the magnified border window immediately so
548 // the user does not see strange artifacts during rotation. The screenshot
549 // used for rotation has already the border. After the rotation is complete
550 // we will show the border.
551 if (isMagnifyingLocked()) {
552 setMagnifiedRegionBorderShownLocked(false, false);
553 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700554 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800555 Message message = mHandler.obtainMessage(
556 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
557 mHandler.sendMessageDelayed(message, delay);
558 }
559 recomputeBoundsLocked();
560 mWindow.updateSize();
561 }
562
563 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
564 if (shown) {
565 mFullRedrawNeeded = true;
566 mOldMagnifiedBounds.set(0, 0, 0, 0);
567 }
568 mWindow.setShown(shown, animate);
569 }
570
571 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
572 MagnificationSpec spec = mMagnificationSpec;
573 mMagnifiedBounds.getBounds(rect);
574 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
575 rect.scale(1.0f / spec.scale);
576 }
577
578 public boolean isMagnifyingLocked() {
579 return mMagnificationSpec.scale > 1.0f;
580 }
581
582 public MagnificationSpec getMagnificationSpecLocked() {
583 return mMagnificationSpec;
584 }
585
586 /** NOTE: This has to be called within a surface transaction. */
587 public void drawWindowIfNeededLocked() {
588 recomputeBoundsLocked();
589 mWindow.drawIfNeeded();
590 }
591
592 public void destroyWindow() {
593 mWindow.releaseSurface();
594 }
595
596 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
597 DisplayContent displayContent = mWindowManagerService
598 .getDefaultDisplayContentLocked();
599 WindowList windowList = displayContent.getWindowList();
600 final int windowCount = windowList.size();
601 for (int i = 0; i < windowCount; i++) {
602 WindowState windowState = windowList.get(i);
603 if ((windowState.isOnScreen() || windowState.mAttrs.type == WindowManager
604 .LayoutParams.TYPE_UNIVERSE_BACKGROUND)
605 && !windowState.mWinAnimator.mEnterAnimationPending) {
606 outWindows.put(windowState.mLayer, windowState);
607 }
608 }
609 }
610
611 private final class ViewportWindow {
612 private static final String SURFACE_TITLE = "Magnification Overlay";
613
614 private static final String PROPERTY_NAME_ALPHA = "alpha";
615
616 private static final int MIN_ALPHA = 0;
617 private static final int MAX_ALPHA = 255;
618
619 private final Region mBounds = new Region();
620 private final Rect mDirtyRect = new Rect();
621 private final Paint mPaint = new Paint();
622
623 private final ValueAnimator mShowHideFrameAnimator;
624 private final SurfaceControl mSurfaceControl;
625 private final Surface mSurface = new Surface();
626
627 private boolean mShown;
628 private int mAlpha;
629
630 private boolean mInvalidated;
631
632 public ViewportWindow(Context context) {
633 SurfaceControl surfaceControl = null;
634 try {
635 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
636 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
637 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
638 SurfaceControl.HIDDEN);
639 } catch (OutOfResourcesException oore) {
640 /* ignore */
641 }
642 mSurfaceControl = surfaceControl;
643 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
644 .getLayerStack());
645 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
646 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
647 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
648 mSurfaceControl.setPosition(0, 0);
649 mSurface.copyFrom(mSurfaceControl);
650
651 TypedValue typedValue = new TypedValue();
652 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
653 typedValue, true);
654 final int borderColor = context.getResources().getColor(typedValue.resourceId);
655
656 mPaint.setStyle(Paint.Style.STROKE);
657 mPaint.setStrokeWidth(mBorderWidth);
658 mPaint.setColor(borderColor);
659
660 Interpolator interpolator = new DecelerateInterpolator(2.5f);
661 final long longAnimationDuration = context.getResources().getInteger(
662 com.android.internal.R.integer.config_longAnimTime);
663
664 mShowHideFrameAnimator = ObjectAnimator.ofInt(this, PROPERTY_NAME_ALPHA,
665 MIN_ALPHA, MAX_ALPHA);
666 mShowHideFrameAnimator.setInterpolator(interpolator);
667 mShowHideFrameAnimator.setDuration(longAnimationDuration);
668 mInvalidated = true;
669 }
670
671 public void setShown(boolean shown, boolean animate) {
672 synchronized (mWindowManagerService.mWindowMap) {
673 if (mShown == shown) {
674 return;
675 }
676 mShown = shown;
677 if (animate) {
678 if (mShowHideFrameAnimator.isRunning()) {
679 mShowHideFrameAnimator.reverse();
680 } else {
681 if (shown) {
682 mShowHideFrameAnimator.start();
683 } else {
684 mShowHideFrameAnimator.reverse();
685 }
686 }
687 } else {
688 mShowHideFrameAnimator.cancel();
689 if (shown) {
690 setAlpha(MAX_ALPHA);
691 } else {
692 setAlpha(MIN_ALPHA);
693 }
694 }
695 if (DEBUG_VIEWPORT_WINDOW) {
696 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
697 }
698 }
699 }
700
701 @SuppressWarnings("unused")
702 // Called reflectively from an animator.
703 public int getAlpha() {
704 synchronized (mWindowManagerService.mWindowMap) {
705 return mAlpha;
706 }
707 }
708
709 public void setAlpha(int alpha) {
710 synchronized (mWindowManagerService.mWindowMap) {
711 if (mAlpha == alpha) {
712 return;
713 }
714 mAlpha = alpha;
715 invalidate(null);
716 if (DEBUG_VIEWPORT_WINDOW) {
717 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
718 }
719 }
720 }
721
722 public void setBounds(Region bounds) {
723 synchronized (mWindowManagerService.mWindowMap) {
724 if (mBounds.equals(bounds)) {
725 return;
726 }
727 mBounds.set(bounds);
728 invalidate(mDirtyRect);
729 if (DEBUG_VIEWPORT_WINDOW) {
730 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
731 }
732 }
733 }
734
735 public void updateSize() {
736 synchronized (mWindowManagerService.mWindowMap) {
737 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
738 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
739 invalidate(mDirtyRect);
740 }
741 }
742
743 public void invalidate(Rect dirtyRect) {
744 if (dirtyRect != null) {
745 mDirtyRect.set(dirtyRect);
746 } else {
747 mDirtyRect.setEmpty();
748 }
749 mInvalidated = true;
750 mWindowManagerService.scheduleAnimationLocked();
751 }
752
753 /** NOTE: This has to be called within a surface transaction. */
754 public void drawIfNeeded() {
755 synchronized (mWindowManagerService.mWindowMap) {
756 if (!mInvalidated) {
757 return;
758 }
759 mInvalidated = false;
760 Canvas canvas = null;
761 try {
762 // Empty dirty rectangle means unspecified.
763 if (mDirtyRect.isEmpty()) {
764 mBounds.getBounds(mDirtyRect);
765 }
766 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
767 canvas = mSurface.lockCanvas(mDirtyRect);
768 if (DEBUG_VIEWPORT_WINDOW) {
769 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
770 }
771 } catch (IllegalArgumentException iae) {
772 /* ignore */
773 } catch (Surface.OutOfResourcesException oore) {
774 /* ignore */
775 }
776 if (canvas == null) {
777 return;
778 }
779 if (DEBUG_VIEWPORT_WINDOW) {
780 Slog.i(LOG_TAG, "Bounds: " + mBounds);
781 }
782 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
783 mPaint.setAlpha(mAlpha);
784 Path path = mBounds.getBoundaryPath();
785 canvas.drawPath(path, mPaint);
786
787 mSurface.unlockCanvasAndPost(canvas);
788
789 if (mAlpha > 0) {
790 mSurfaceControl.show();
791 } else {
792 mSurfaceControl.hide();
793 }
794 }
795 }
796
797 public void releaseSurface() {
798 mSurfaceControl.release();
799 mSurface.release();
800 }
801 }
802 }
803
804 private class MyHandler extends Handler {
805 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
806 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
807 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
808 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
809 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
810
811 public MyHandler(Looper looper) {
812 super(looper);
813 }
814
815 @Override
816 public void handleMessage(Message message) {
817 switch (message.what) {
818 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
819 Region bounds = (Region) message.obj;
820 mCallbacks.onMagnifedBoundsChanged(bounds);
821 bounds.recycle();
822 } break;
823
824 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
825 SomeArgs args = (SomeArgs) message.obj;
826 final int left = args.argi1;
827 final int top = args.argi2;
828 final int right = args.argi3;
829 final int bottom = args.argi4;
830 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
831 args.recycle();
832 } break;
833
834 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
835 mCallbacks.onUserContextChanged();
836 } break;
837
838 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
839 final int rotation = message.arg1;
840 mCallbacks.onRotationChanged(rotation);
841 } break;
842
843 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
844 synchronized (mWindowManagerService.mWindowMap) {
845 if (mMagnifedViewport.isMagnifyingLocked()) {
846 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
847 mWindowManagerService.scheduleAnimationLocked();
848 }
849 }
850 } break;
851 }
852 }
853 }
854 }
855
856 /**
857 * This class encapsulates the functionality related to computing the windows
858 * reported for accessibility purposes. These windows are all windows a sighted
859 * user can see on the screen.
860 */
861 private static final class WindowsForAccessibilityObserver {
862 private static final String LOG_TAG = "WindowsForAccessibilityObserver";
863
864 private static final boolean DEBUG = false;
865
866 private final SparseArray<WindowState> mTempWindowStates =
867 new SparseArray<WindowState>();
868
869 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
870
871 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
872
873 private final RectF mTempRectF = new RectF();
874
875 private final Matrix mTempMatrix = new Matrix();
876
877 private final Point mTempPoint = new Point();
878
879 private final Rect mTempRect = new Rect();
880
881 private final Region mTempRegion = new Region();
882
883 private final Region mTempRegion1 = new Region();
884
885 private final Context mContext;
886
887 private final WindowManagerService mWindowManagerService;
888
889 private final Handler mHandler;
890
891 private final WindowsForAccessibilityCallback mCallback;
892
Svetoslavf7174e82014-06-12 11:29:35 -0700893 private final long mRecurringAccessibilityEventsIntervalMillis;
894
Svetoslav8e3feb12014-02-24 13:46:47 -0800895 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
896 WindowsForAccessibilityCallback callback) {
897 mContext = windowManagerService.mContext;
898 mWindowManagerService = windowManagerService;
899 mCallback = callback;
900 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700901 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
902 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800903 computeChangedWindows();
904 }
905
Svetoslavf7174e82014-06-12 11:29:35 -0700906 public void scheduleComputeChangedWindowsLocked() {
907 // If focus changed, compute changed windows immediately as the focused window
908 // is used by the accessibility manager service to determine the active window.
909 if (mWindowManagerService.mCurrentFocus != null
910 && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
911 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
912 computeChangedWindows();
913 } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
914 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
915 mRecurringAccessibilityEventsIntervalMillis);
916 }
917 }
918
Svetoslav8e3feb12014-02-24 13:46:47 -0800919 public void computeChangedWindows() {
920 if (DEBUG) {
921 Slog.i(LOG_TAG, "computeChangedWindows()");
922 }
923
924 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700925 // Do not send the windows if there is no current focus as
926 // the window manager is still looking for where to put it.
927 // We will do the work when we get a focus change callback.
928 if (mWindowManagerService.mCurrentFocus == null) {
929 return;
930 }
931
Svetoslav8e3feb12014-02-24 13:46:47 -0800932 WindowManager windowManager = (WindowManager)
933 mContext.getSystemService(Context.WINDOW_SERVICE);
934 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
935 final int screenWidth = mTempPoint.x;
936 final int screenHeight = mTempPoint.y;
937
938 Region unaccountedSpace = mTempRegion;
939 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
940
941 SparseArray<WindowState> visibleWindows = mTempWindowStates;
942 populateVisibleWindowsOnScreenLocked(visibleWindows);
943
944 List<WindowInfo> windows = new ArrayList<WindowInfo>();
945
946 Set<IBinder> addedWindows = mTempBinderSet;
947 addedWindows.clear();
948
Svetoslavf7174e82014-06-12 11:29:35 -0700949 boolean focusedWindowAdded = false;
950
Svetoslav8e3feb12014-02-24 13:46:47 -0800951 final int visibleWindowCount = visibleWindows.size();
952 for (int i = visibleWindowCount - 1; i >= 0; i--) {
953 WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -0800954
Svetoslavf7174e82014-06-12 11:29:35 -0700955 // Compute the bounds in the screen.
Svetoslav8e3feb12014-02-24 13:46:47 -0800956 Rect boundsInScreen = mTempRect;
Svetoslavf7174e82014-06-12 11:29:35 -0700957 computeWindowBoundsInScreen(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -0800958
959 final int flags = windowState.mAttrs.flags;
960
961 // If the window is not touchable, do not report it but take into account
962 // the space it takes since the content behind it cannot be touched.
Svetoslavf7174e82014-06-12 11:29:35 -0700963 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800964 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
965 Region.Op.DIFFERENCE);
966 continue;
967 }
968
969 // If the window is completely covered by other windows - ignore.
970 if (unaccountedSpace.quickReject(boundsInScreen)) {
971 continue;
972 }
973
974 // Add windows of certain types not covered by modal windows.
975 if (isReportedWindowType(windowState.mAttrs.type)) {
976 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -0700977 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -0800978 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -0800979 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -0700980 if (windowState.isFocused()) {
981 focusedWindowAdded = true;
982 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800983 }
984
985 // Account for the space this window takes.
986 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
987 Region.Op.REVERSE_DIFFERENCE);
988
989 // We figured out what is touchable for the entire screen - done.
990 if (unaccountedSpace.isEmpty()) {
991 break;
992 }
993
994 // If a window is modal, no other below can be touched - done.
995 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
996 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
997 break;
998 }
999 }
1000
Svetoslavf7174e82014-06-12 11:29:35 -07001001 // Always report the focused window.
1002 if (!focusedWindowAdded) {
1003 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1004 WindowState windowState = visibleWindows.valueAt(i);
1005 if (windowState.isFocused()) {
1006 // Compute the bounds in the screen.
1007 Rect boundsInScreen = mTempRect;
1008 computeWindowBoundsInScreen(windowState, boundsInScreen);
1009
1010 // Add the window to the ones to be reported.
1011 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1012 boundsInScreen);
1013 addedWindows.add(window.token);
1014 windows.add(window);
1015 break;
1016 }
1017 }
1018 }
1019
Svetoslav8e3feb12014-02-24 13:46:47 -08001020 // Remove child/parent references to windows that were not added.
1021 final int windowCount = windows.size();
1022 for (int i = 0; i < windowCount; i++) {
1023 WindowInfo window = windows.get(i);
1024 if (!addedWindows.contains(window.parentToken)) {
1025 window.parentToken = null;
1026 }
1027 if (window.childTokens != null) {
1028 final int childTokenCount = window.childTokens.size();
1029 for (int j = childTokenCount - 1; j >= 0; j--) {
1030 if (!addedWindows.contains(window.childTokens.get(j))) {
1031 window.childTokens.remove(j);
1032 }
1033 }
1034 // Leave the child token list if empty.
1035 }
1036 }
1037
1038 visibleWindows.clear();
1039 addedWindows.clear();
1040
1041 // We computed the windows and if they changed notify the client.
1042 boolean windowsChanged = false;
1043 if (mOldWindows.size() != windows.size()) {
1044 // Different size means something changed.
1045 windowsChanged = true;
1046 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1047 // Since we always traverse windows from high to low layer
1048 // the old and new windows at the same index should be the
1049 // same, otherwise something changed.
1050 for (int i = 0; i < windowCount; i++) {
1051 WindowInfo oldWindow = mOldWindows.get(i);
1052 WindowInfo newWindow = windows.get(i);
1053 // We do not care for layer changes given the window
1054 // order does not change. This brings no new information
1055 // to the clients.
1056 if (windowChangedNoLayer(oldWindow, newWindow)) {
1057 windowsChanged = true;
1058 break;
1059 }
1060 }
1061 }
1062
1063 if (windowsChanged) {
1064 if (DEBUG) {
1065 Log.i(LOG_TAG, "Windows changed:" + windows);
1066 }
1067 // Remember the old windows to detect changes.
1068 cacheWindows(windows);
1069 // Announce the change.
1070 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
1071 windows).sendToTarget();
1072 } else {
1073 if (DEBUG) {
1074 Log.i(LOG_TAG, "No windows changed.");
1075 }
1076 // Recycle the nodes as we do not need them.
1077 clearAndRecycleWindows(windows);
1078 }
1079 }
1080 }
1081
Svetoslavf7174e82014-06-12 11:29:35 -07001082 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1083 // Get the touchable frame.
1084 Region touchableRegion = mTempRegion1;
1085 windowState.getTouchableRegion(touchableRegion);
1086 Rect touchableFrame = mTempRect;
1087 touchableRegion.getBounds(touchableFrame);
1088
1089 // Move to origin as all transforms are captured by the matrix.
1090 RectF windowFrame = mTempRectF;
1091 windowFrame.set(touchableFrame);
1092 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1093
1094 // Map the frame to get what appears on the screen.
1095 Matrix matrix = mTempMatrix;
1096 populateTransformationMatrixLocked(windowState, matrix);
1097 matrix.mapRect(windowFrame);
1098
1099 // Got the bounds.
1100 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1101 (int) windowFrame.right, (int) windowFrame.bottom);
1102 }
1103
1104 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1105 Rect boundsInScreen) {
1106 WindowInfo window = WindowInfo.obtain();
1107 window.type = windowState.mAttrs.type;
1108 window.layer = windowState.mLayer;
1109 window.token = windowState.mClient.asBinder();
1110
1111 WindowState attachedWindow = windowState.mAttachedWindow;
1112 if (attachedWindow != null) {
1113 window.parentToken = attachedWindow.mClient.asBinder();
1114 }
1115
1116 window.focused = windowState.isFocused();
1117 window.boundsInScreen.set(boundsInScreen);
1118
1119 final int childCount = windowState.mChildWindows.size();
1120 if (childCount > 0) {
1121 if (window.childTokens == null) {
1122 window.childTokens = new ArrayList<IBinder>();
1123 }
1124 for (int j = 0; j < childCount; j++) {
1125 WindowState child = windowState.mChildWindows.get(j);
1126 window.childTokens.add(child.mClient.asBinder());
1127 }
1128 }
1129
1130 return window;
1131 }
1132
Svetoslav8e3feb12014-02-24 13:46:47 -08001133 private void cacheWindows(List<WindowInfo> windows) {
1134 final int oldWindowCount = mOldWindows.size();
1135 for (int i = oldWindowCount - 1; i >= 0; i--) {
1136 mOldWindows.remove(i).recycle();
1137 }
1138 final int newWindowCount = windows.size();
1139 for (int i = 0; i < newWindowCount; i++) {
1140 WindowInfo newWindow = windows.get(i);
1141 mOldWindows.add(WindowInfo.obtain(newWindow));
1142 }
1143 }
1144
1145 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1146 if (oldWindow == newWindow) {
1147 return false;
1148 }
Svetoslavf7174e82014-06-12 11:29:35 -07001149 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001150 return true;
1151 }
Svetoslavf7174e82014-06-12 11:29:35 -07001152 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001153 return true;
1154 }
1155 if (oldWindow.type != newWindow.type) {
1156 return true;
1157 }
1158 if (oldWindow.focused != newWindow.focused) {
1159 return true;
1160 }
1161 if (oldWindow.token == null) {
1162 if (newWindow.token != null) {
1163 return true;
1164 }
1165 } else if (!oldWindow.token.equals(newWindow.token)) {
1166 return true;
1167 }
1168 if (oldWindow.parentToken == null) {
1169 if (newWindow.parentToken != null) {
1170 return true;
1171 }
1172 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1173 return true;
1174 }
1175 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1176 return true;
1177 }
1178 if (oldWindow.childTokens != null && newWindow.childTokens != null
1179 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1180 return true;
1181 }
1182 return false;
1183 }
1184
1185 private void clearAndRecycleWindows(List<WindowInfo> windows) {
1186 final int windowCount = windows.size();
1187 for (int i = windowCount - 1; i >= 0; i--) {
1188 windows.remove(i).recycle();
1189 }
1190 }
1191
1192 private static boolean isReportedWindowType(int windowType) {
1193 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1194 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1195 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1196 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1197 && windowType != WindowManager.LayoutParams.TYPE_DRAG
1198 && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
1199 && windowType != WindowManager.LayoutParams.TYPE_POINTER
1200 && windowType != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
1201 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1202 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1203 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1204 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1205 }
1206
1207 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1208 DisplayContent displayContent = mWindowManagerService
1209 .getDefaultDisplayContentLocked();
1210 WindowList windowList = displayContent.getWindowList();
1211 final int windowCount = windowList.size();
1212 for (int i = 0; i < windowCount; i++) {
1213 WindowState windowState = windowList.get(i);
1214 if (windowState.isVisibleLw()) {
1215 outWindows.put(windowState.mLayer, windowState);
1216 }
1217 }
1218 }
1219
1220 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001221 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
1222 public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
Svetoslav8e3feb12014-02-24 13:46:47 -08001223
1224 public MyHandler(Looper looper) {
1225 super(looper, null, false);
1226 }
1227
1228 @Override
1229 @SuppressWarnings("unchecked")
1230 public void handleMessage(Message message) {
1231 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001232 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1233 computeChangedWindows();
1234 } break;
1235
Svetoslav8e3feb12014-02-24 13:46:47 -08001236 case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
1237 List<WindowInfo> windows = (List<WindowInfo>) message.obj;
1238 mCallback.onWindowsForAccessibilityChanged(windows);
1239 clearAndRecycleWindows(windows);
1240 } break;
1241 }
1242 }
1243 }
1244 }
1245}