blob: fde703d63dc3c28a987ba50804e305e39591d7b9 [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:
Adrian Roos9a645132014-10-08 02:59:56 +0200349 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800350 Rect magnifiedRegionBounds = mTempRect2;
351 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
352 magnifiedRegionBounds);
353 Rect touchableRegionBounds = mTempRect1;
354 windowState.getTouchableRegion(mTempRegion1);
355 mTempRegion1.getBounds(touchableRegionBounds);
356 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
357 mCallbacks.onRectangleOnScreenRequested(
358 touchableRegionBounds.left,
359 touchableRegionBounds.top,
360 touchableRegionBounds.right,
361 touchableRegionBounds.bottom);
362 }
363 } break;
364 } break;
365 }
366 }
367 }
368
369 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
370 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
371 if (spec != null && !spec.isNop()) {
372 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
373 final int windowType = windowState.mAttrs.type;
374 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
375 && !policy.canMagnifyWindow(windowType)) {
376 return null;
377 }
378 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
379 return null;
380 }
381 }
382 return spec;
383 }
384
385 public void destroyLocked() {
386 mMagnifedViewport.destroyWindow();
387 }
388
389 /** NOTE: This has to be called within a surface transaction. */
390 public void drawMagnifiedRegionBorderIfNeededLocked() {
391 mMagnifedViewport.drawWindowIfNeededLocked();
392 }
393
394 private final class MagnifiedViewport {
395
396 private static final int DEFAUTLT_BORDER_WIDTH_DIP = 5;
397
398 private final SparseArray<WindowState> mTempWindowStates =
399 new SparseArray<WindowState>();
400
401 private final RectF mTempRectF = new RectF();
402
403 private final Point mTempPoint = new Point();
404
405 private final Matrix mTempMatrix = new Matrix();
406
407 private final Region mMagnifiedBounds = new Region();
408 private final Region mOldMagnifiedBounds = new Region();
409
410 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
411
412 private final WindowManager mWindowManager;
413
Svetoslav7505e332014-08-22 12:14:28 -0700414 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800415 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700416 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800417
418 private final ViewportWindow mWindow;
419
420 private boolean mFullRedrawNeeded;
421
422 public MagnifiedViewport() {
423 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Svetoslav7505e332014-08-22 12:14:28 -0700424 mBorderWidth = TypedValue.applyDimension(
Svetoslav8e3feb12014-02-24 13:46:47 -0800425 TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP,
426 mContext.getResources().getDisplayMetrics());
Svetoslav7505e332014-08-22 12:14:28 -0700427 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
428 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800429 mWindow = new ViewportWindow(mContext);
430 recomputeBoundsLocked();
431 }
432
433 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
434 if (spec != null) {
435 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
436 } else {
437 mMagnificationSpec.clear();
438 }
439 // If this message is pending we are in a rotation animation and do not want
440 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700441 if (!mHandler.hasMessages(
442 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800443 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
444 }
445 }
446
447 public void recomputeBoundsLocked() {
448 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
449 final int screenWidth = mTempPoint.x;
450 final int screenHeight = mTempPoint.y;
451
452 Region magnifiedBounds = mMagnifiedBounds;
453 magnifiedBounds.set(0, 0, 0, 0);
454
455 Region availableBounds = mTempRegion1;
456 availableBounds.set(0, 0, screenWidth, screenHeight);
457
458 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700459 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800460
461 SparseArray<WindowState> visibleWindows = mTempWindowStates;
462 visibleWindows.clear();
463 populateWindowsOnScreenLocked(visibleWindows);
464
465 final int visibleWindowCount = visibleWindows.size();
466 for (int i = visibleWindowCount - 1; i >= 0; i--) {
467 WindowState windowState = visibleWindows.valueAt(i);
468 if (windowState.mAttrs.type == WindowManager
469 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
470 continue;
471 }
472
473 Region windowBounds = mTempRegion2;
474 Matrix matrix = mTempMatrix;
475 populateTransformationMatrixLocked(windowState, matrix);
476 RectF windowFrame = mTempRectF;
477
478 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
479 windowFrame.set(windowState.mFrame);
480 windowFrame.offset(-windowFrame.left, -windowFrame.top);
481 matrix.mapRect(windowFrame);
482 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
483 (int) windowFrame.right, (int) windowFrame.bottom);
484 magnifiedBounds.op(windowBounds, Region.Op.UNION);
485 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
486 } else {
487 Region touchableRegion = mTempRegion3;
488 windowState.getTouchableRegion(touchableRegion);
489 Rect touchableFrame = mTempRect1;
490 touchableRegion.getBounds(touchableFrame);
491 windowFrame.set(touchableFrame);
492 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
493 matrix.mapRect(windowFrame);
494 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
495 (int) windowFrame.right, (int) windowFrame.bottom);
496 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
497 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
498 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
499 }
500
501 Region accountedBounds = mTempRegion2;
502 accountedBounds.set(magnifiedBounds);
503 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
504 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
505
506 if (accountedBounds.isRect()) {
507 Rect accountedFrame = mTempRect1;
508 accountedBounds.getBounds(accountedFrame);
509 if (accountedFrame.width() == screenWidth
510 && accountedFrame.height() == screenHeight) {
511 break;
512 }
513 }
514 }
515
516 visibleWindows.clear();
517
Svetoslav7505e332014-08-22 12:14:28 -0700518 magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
519 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800520 Region.Op.INTERSECT);
521
522 if (!mOldMagnifiedBounds.equals(magnifiedBounds)) {
523 Region bounds = Region.obtain();
524 bounds.set(magnifiedBounds);
525 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED,
526 bounds).sendToTarget();
527
528 mWindow.setBounds(magnifiedBounds);
529 Rect dirtyRect = mTempRect1;
530 if (mFullRedrawNeeded) {
531 mFullRedrawNeeded = false;
Svetoslav7505e332014-08-22 12:14:28 -0700532 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
533 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset);
Svetoslav8e3feb12014-02-24 13:46:47 -0800534 mWindow.invalidate(dirtyRect);
535 } else {
536 Region dirtyRegion = mTempRegion3;
537 dirtyRegion.set(magnifiedBounds);
538 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
539 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
540 dirtyRegion.getBounds(dirtyRect);
541 mWindow.invalidate(dirtyRect);
542 }
543
544 mOldMagnifiedBounds.set(magnifiedBounds);
545 }
546 }
547
548 public void onRotationChangedLocked() {
549 // If we are magnifying, hide the magnified border window immediately so
550 // the user does not see strange artifacts during rotation. The screenshot
551 // used for rotation has already the border. After the rotation is complete
552 // we will show the border.
553 if (isMagnifyingLocked()) {
554 setMagnifiedRegionBorderShownLocked(false, false);
555 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700556 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800557 Message message = mHandler.obtainMessage(
558 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
559 mHandler.sendMessageDelayed(message, delay);
560 }
561 recomputeBoundsLocked();
562 mWindow.updateSize();
563 }
564
565 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
566 if (shown) {
567 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700568 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800569 }
570 mWindow.setShown(shown, animate);
571 }
572
573 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
574 MagnificationSpec spec = mMagnificationSpec;
575 mMagnifiedBounds.getBounds(rect);
576 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
577 rect.scale(1.0f / spec.scale);
578 }
579
580 public boolean isMagnifyingLocked() {
581 return mMagnificationSpec.scale > 1.0f;
582 }
583
584 public MagnificationSpec getMagnificationSpecLocked() {
585 return mMagnificationSpec;
586 }
587
588 /** NOTE: This has to be called within a surface transaction. */
589 public void drawWindowIfNeededLocked() {
590 recomputeBoundsLocked();
591 mWindow.drawIfNeeded();
592 }
593
594 public void destroyWindow() {
595 mWindow.releaseSurface();
596 }
597
598 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
599 DisplayContent displayContent = mWindowManagerService
600 .getDefaultDisplayContentLocked();
601 WindowList windowList = displayContent.getWindowList();
602 final int windowCount = windowList.size();
603 for (int i = 0; i < windowCount; i++) {
604 WindowState windowState = windowList.get(i);
605 if ((windowState.isOnScreen() || windowState.mAttrs.type == WindowManager
606 .LayoutParams.TYPE_UNIVERSE_BACKGROUND)
607 && !windowState.mWinAnimator.mEnterAnimationPending) {
608 outWindows.put(windowState.mLayer, windowState);
609 }
610 }
611 }
612
613 private final class ViewportWindow {
614 private static final String SURFACE_TITLE = "Magnification Overlay";
615
Svetoslav8e3feb12014-02-24 13:46:47 -0800616 private final Region mBounds = new Region();
617 private final Rect mDirtyRect = new Rect();
618 private final Paint mPaint = new Paint();
619
Svetoslav8e3feb12014-02-24 13:46:47 -0800620 private final SurfaceControl mSurfaceControl;
621 private final Surface mSurface = new Surface();
622
Svet Ganovb21df802014-09-01 19:06:33 -0700623 private final AnimationController mAnimationController;
624
Svetoslav8e3feb12014-02-24 13:46:47 -0800625 private boolean mShown;
626 private int mAlpha;
627
628 private boolean mInvalidated;
629
630 public ViewportWindow(Context context) {
631 SurfaceControl surfaceControl = null;
632 try {
633 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
634 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
635 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
636 SurfaceControl.HIDDEN);
637 } catch (OutOfResourcesException oore) {
638 /* ignore */
639 }
640 mSurfaceControl = surfaceControl;
641 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
642 .getLayerStack());
643 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
644 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
645 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
646 mSurfaceControl.setPosition(0, 0);
647 mSurface.copyFrom(mSurfaceControl);
648
Svet Ganovb21df802014-09-01 19:06:33 -0700649 mAnimationController = new AnimationController(context,
650 mWindowManagerService.mH.getLooper());
651
Svetoslav8e3feb12014-02-24 13:46:47 -0800652 TypedValue typedValue = new TypedValue();
653 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
654 typedValue, true);
655 final int borderColor = context.getResources().getColor(typedValue.resourceId);
656
657 mPaint.setStyle(Paint.Style.STROKE);
658 mPaint.setStrokeWidth(mBorderWidth);
659 mPaint.setColor(borderColor);
660
Svetoslav8e3feb12014-02-24 13:46:47 -0800661 mInvalidated = true;
662 }
663
664 public void setShown(boolean shown, boolean animate) {
665 synchronized (mWindowManagerService.mWindowMap) {
666 if (mShown == shown) {
667 return;
668 }
669 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700670 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800671 if (DEBUG_VIEWPORT_WINDOW) {
672 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
673 }
674 }
675 }
676
677 @SuppressWarnings("unused")
678 // Called reflectively from an animator.
679 public int getAlpha() {
680 synchronized (mWindowManagerService.mWindowMap) {
681 return mAlpha;
682 }
683 }
684
685 public void setAlpha(int alpha) {
686 synchronized (mWindowManagerService.mWindowMap) {
687 if (mAlpha == alpha) {
688 return;
689 }
690 mAlpha = alpha;
691 invalidate(null);
692 if (DEBUG_VIEWPORT_WINDOW) {
693 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
694 }
695 }
696 }
697
698 public void setBounds(Region bounds) {
699 synchronized (mWindowManagerService.mWindowMap) {
700 if (mBounds.equals(bounds)) {
701 return;
702 }
703 mBounds.set(bounds);
704 invalidate(mDirtyRect);
705 if (DEBUG_VIEWPORT_WINDOW) {
706 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
707 }
708 }
709 }
710
711 public void updateSize() {
712 synchronized (mWindowManagerService.mWindowMap) {
713 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
714 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
715 invalidate(mDirtyRect);
716 }
717 }
718
719 public void invalidate(Rect dirtyRect) {
720 if (dirtyRect != null) {
721 mDirtyRect.set(dirtyRect);
722 } else {
723 mDirtyRect.setEmpty();
724 }
725 mInvalidated = true;
726 mWindowManagerService.scheduleAnimationLocked();
727 }
728
729 /** NOTE: This has to be called within a surface transaction. */
730 public void drawIfNeeded() {
731 synchronized (mWindowManagerService.mWindowMap) {
732 if (!mInvalidated) {
733 return;
734 }
735 mInvalidated = false;
736 Canvas canvas = null;
737 try {
738 // Empty dirty rectangle means unspecified.
739 if (mDirtyRect.isEmpty()) {
740 mBounds.getBounds(mDirtyRect);
741 }
742 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
743 canvas = mSurface.lockCanvas(mDirtyRect);
744 if (DEBUG_VIEWPORT_WINDOW) {
745 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
746 }
747 } catch (IllegalArgumentException iae) {
748 /* ignore */
749 } catch (Surface.OutOfResourcesException oore) {
750 /* ignore */
751 }
752 if (canvas == null) {
753 return;
754 }
755 if (DEBUG_VIEWPORT_WINDOW) {
756 Slog.i(LOG_TAG, "Bounds: " + mBounds);
757 }
758 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
759 mPaint.setAlpha(mAlpha);
760 Path path = mBounds.getBoundaryPath();
761 canvas.drawPath(path, mPaint);
762
763 mSurface.unlockCanvasAndPost(canvas);
764
765 if (mAlpha > 0) {
766 mSurfaceControl.show();
767 } else {
768 mSurfaceControl.hide();
769 }
770 }
771 }
772
773 public void releaseSurface() {
774 mSurfaceControl.release();
775 mSurface.release();
776 }
Svet Ganovb21df802014-09-01 19:06:33 -0700777
778 private final class AnimationController extends Handler {
779 private static final String PROPERTY_NAME_ALPHA = "alpha";
780
781 private static final int MIN_ALPHA = 0;
782 private static final int MAX_ALPHA = 255;
783
784 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
785
786 private final ValueAnimator mShowHideFrameAnimator;
787
788 public AnimationController(Context context, Looper looper) {
789 super(looper);
790 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
791 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
792
793 Interpolator interpolator = new DecelerateInterpolator(2.5f);
794 final long longAnimationDuration = context.getResources().getInteger(
795 com.android.internal.R.integer.config_longAnimTime);
796
797 mShowHideFrameAnimator.setInterpolator(interpolator);
798 mShowHideFrameAnimator.setDuration(longAnimationDuration);
799 }
800
801 public void onFrameShownStateChanged(boolean shown, boolean animate) {
802 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
803 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
804 }
805
806 @Override
807 public void handleMessage(Message message) {
808 switch (message.what) {
809 case MSG_FRAME_SHOWN_STATE_CHANGED: {
810 final boolean shown = message.arg1 == 1;
811 final boolean animate = message.arg2 == 1;
812
813 if (animate) {
814 if (mShowHideFrameAnimator.isRunning()) {
815 mShowHideFrameAnimator.reverse();
816 } else {
817 if (shown) {
818 mShowHideFrameAnimator.start();
819 } else {
820 mShowHideFrameAnimator.reverse();
821 }
822 }
823 } else {
824 mShowHideFrameAnimator.cancel();
825 if (shown) {
826 setAlpha(MAX_ALPHA);
827 } else {
828 setAlpha(MIN_ALPHA);
829 }
830 }
831 } break;
832 }
833 }
834 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800835 }
836 }
837
838 private class MyHandler extends Handler {
839 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
840 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
841 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
842 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
843 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
844
845 public MyHandler(Looper looper) {
846 super(looper);
847 }
848
849 @Override
850 public void handleMessage(Message message) {
851 switch (message.what) {
852 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
853 Region bounds = (Region) message.obj;
854 mCallbacks.onMagnifedBoundsChanged(bounds);
855 bounds.recycle();
856 } break;
857
858 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
859 SomeArgs args = (SomeArgs) message.obj;
860 final int left = args.argi1;
861 final int top = args.argi2;
862 final int right = args.argi3;
863 final int bottom = args.argi4;
864 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
865 args.recycle();
866 } break;
867
868 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
869 mCallbacks.onUserContextChanged();
870 } break;
871
872 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
873 final int rotation = message.arg1;
874 mCallbacks.onRotationChanged(rotation);
875 } break;
876
877 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
878 synchronized (mWindowManagerService.mWindowMap) {
879 if (mMagnifedViewport.isMagnifyingLocked()) {
880 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
881 mWindowManagerService.scheduleAnimationLocked();
882 }
883 }
884 } break;
885 }
886 }
887 }
888 }
889
890 /**
891 * This class encapsulates the functionality related to computing the windows
892 * reported for accessibility purposes. These windows are all windows a sighted
893 * user can see on the screen.
894 */
895 private static final class WindowsForAccessibilityObserver {
896 private static final String LOG_TAG = "WindowsForAccessibilityObserver";
897
898 private static final boolean DEBUG = false;
899
900 private final SparseArray<WindowState> mTempWindowStates =
901 new SparseArray<WindowState>();
902
903 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
904
905 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
906
907 private final RectF mTempRectF = new RectF();
908
909 private final Matrix mTempMatrix = new Matrix();
910
911 private final Point mTempPoint = new Point();
912
913 private final Rect mTempRect = new Rect();
914
915 private final Region mTempRegion = new Region();
916
917 private final Region mTempRegion1 = new Region();
918
919 private final Context mContext;
920
921 private final WindowManagerService mWindowManagerService;
922
923 private final Handler mHandler;
924
925 private final WindowsForAccessibilityCallback mCallback;
926
Svetoslavf7174e82014-06-12 11:29:35 -0700927 private final long mRecurringAccessibilityEventsIntervalMillis;
928
Svetoslav8e3feb12014-02-24 13:46:47 -0800929 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
930 WindowsForAccessibilityCallback callback) {
931 mContext = windowManagerService.mContext;
932 mWindowManagerService = windowManagerService;
933 mCallback = callback;
934 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700935 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
936 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800937 computeChangedWindows();
938 }
939
Svetoslavf7174e82014-06-12 11:29:35 -0700940 public void scheduleComputeChangedWindowsLocked() {
941 // If focus changed, compute changed windows immediately as the focused window
942 // is used by the accessibility manager service to determine the active window.
943 if (mWindowManagerService.mCurrentFocus != null
944 && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
945 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
946 computeChangedWindows();
947 } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
948 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
949 mRecurringAccessibilityEventsIntervalMillis);
950 }
951 }
952
Svetoslav8e3feb12014-02-24 13:46:47 -0800953 public void computeChangedWindows() {
954 if (DEBUG) {
955 Slog.i(LOG_TAG, "computeChangedWindows()");
956 }
957
958 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -0700959 // Do not send the windows if there is no current focus as
960 // the window manager is still looking for where to put it.
961 // We will do the work when we get a focus change callback.
962 if (mWindowManagerService.mCurrentFocus == null) {
963 return;
964 }
965
Svetoslav8e3feb12014-02-24 13:46:47 -0800966 WindowManager windowManager = (WindowManager)
967 mContext.getSystemService(Context.WINDOW_SERVICE);
968 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
969 final int screenWidth = mTempPoint.x;
970 final int screenHeight = mTempPoint.y;
971
972 Region unaccountedSpace = mTempRegion;
973 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
974
975 SparseArray<WindowState> visibleWindows = mTempWindowStates;
976 populateVisibleWindowsOnScreenLocked(visibleWindows);
977
978 List<WindowInfo> windows = new ArrayList<WindowInfo>();
979
980 Set<IBinder> addedWindows = mTempBinderSet;
981 addedWindows.clear();
982
Svetoslavf7174e82014-06-12 11:29:35 -0700983 boolean focusedWindowAdded = false;
984
Svetoslav8e3feb12014-02-24 13:46:47 -0800985 final int visibleWindowCount = visibleWindows.size();
986 for (int i = visibleWindowCount - 1; i >= 0; i--) {
987 WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -0800988
Svetoslavf7174e82014-06-12 11:29:35 -0700989 // Compute the bounds in the screen.
Svetoslav8e3feb12014-02-24 13:46:47 -0800990 Rect boundsInScreen = mTempRect;
Svetoslavf7174e82014-06-12 11:29:35 -0700991 computeWindowBoundsInScreen(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -0800992
993 final int flags = windowState.mAttrs.flags;
994
995 // If the window is not touchable, do not report it but take into account
996 // the space it takes since the content behind it cannot be touched.
Svetoslavf7174e82014-06-12 11:29:35 -0700997 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800998 continue;
999 }
1000
1001 // If the window is completely covered by other windows - ignore.
1002 if (unaccountedSpace.quickReject(boundsInScreen)) {
1003 continue;
1004 }
1005
1006 // Add windows of certain types not covered by modal windows.
1007 if (isReportedWindowType(windowState.mAttrs.type)) {
1008 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001009 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001010 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001011 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001012 if (windowState.isFocused()) {
1013 focusedWindowAdded = true;
1014 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001015 }
1016
1017 // Account for the space this window takes.
1018 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1019 Region.Op.REVERSE_DIFFERENCE);
1020
1021 // We figured out what is touchable for the entire screen - done.
1022 if (unaccountedSpace.isEmpty()) {
1023 break;
1024 }
1025
1026 // If a window is modal, no other below can be touched - done.
1027 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1028 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
1029 break;
1030 }
1031 }
1032
Svetoslavf7174e82014-06-12 11:29:35 -07001033 // Always report the focused window.
1034 if (!focusedWindowAdded) {
1035 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1036 WindowState windowState = visibleWindows.valueAt(i);
1037 if (windowState.isFocused()) {
1038 // Compute the bounds in the screen.
1039 Rect boundsInScreen = mTempRect;
1040 computeWindowBoundsInScreen(windowState, boundsInScreen);
1041
1042 // Add the window to the ones to be reported.
1043 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1044 boundsInScreen);
1045 addedWindows.add(window.token);
1046 windows.add(window);
1047 break;
1048 }
1049 }
1050 }
1051
Svetoslav8e3feb12014-02-24 13:46:47 -08001052 // Remove child/parent references to windows that were not added.
1053 final int windowCount = windows.size();
1054 for (int i = 0; i < windowCount; i++) {
1055 WindowInfo window = windows.get(i);
1056 if (!addedWindows.contains(window.parentToken)) {
1057 window.parentToken = null;
1058 }
1059 if (window.childTokens != null) {
1060 final int childTokenCount = window.childTokens.size();
1061 for (int j = childTokenCount - 1; j >= 0; j--) {
1062 if (!addedWindows.contains(window.childTokens.get(j))) {
1063 window.childTokens.remove(j);
1064 }
1065 }
1066 // Leave the child token list if empty.
1067 }
1068 }
1069
1070 visibleWindows.clear();
1071 addedWindows.clear();
1072
1073 // We computed the windows and if they changed notify the client.
1074 boolean windowsChanged = false;
1075 if (mOldWindows.size() != windows.size()) {
1076 // Different size means something changed.
1077 windowsChanged = true;
1078 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1079 // Since we always traverse windows from high to low layer
1080 // the old and new windows at the same index should be the
1081 // same, otherwise something changed.
1082 for (int i = 0; i < windowCount; i++) {
1083 WindowInfo oldWindow = mOldWindows.get(i);
1084 WindowInfo newWindow = windows.get(i);
1085 // We do not care for layer changes given the window
1086 // order does not change. This brings no new information
1087 // to the clients.
1088 if (windowChangedNoLayer(oldWindow, newWindow)) {
1089 windowsChanged = true;
1090 break;
1091 }
1092 }
1093 }
1094
1095 if (windowsChanged) {
1096 if (DEBUG) {
1097 Log.i(LOG_TAG, "Windows changed:" + windows);
1098 }
1099 // Remember the old windows to detect changes.
1100 cacheWindows(windows);
1101 // Announce the change.
1102 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
1103 windows).sendToTarget();
1104 } else {
1105 if (DEBUG) {
1106 Log.i(LOG_TAG, "No windows changed.");
1107 }
1108 // Recycle the nodes as we do not need them.
1109 clearAndRecycleWindows(windows);
1110 }
1111 }
1112 }
1113
Svetoslavf7174e82014-06-12 11:29:35 -07001114 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1115 // Get the touchable frame.
1116 Region touchableRegion = mTempRegion1;
1117 windowState.getTouchableRegion(touchableRegion);
1118 Rect touchableFrame = mTempRect;
1119 touchableRegion.getBounds(touchableFrame);
1120
1121 // Move to origin as all transforms are captured by the matrix.
1122 RectF windowFrame = mTempRectF;
1123 windowFrame.set(touchableFrame);
1124 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1125
1126 // Map the frame to get what appears on the screen.
1127 Matrix matrix = mTempMatrix;
1128 populateTransformationMatrixLocked(windowState, matrix);
1129 matrix.mapRect(windowFrame);
1130
1131 // Got the bounds.
1132 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1133 (int) windowFrame.right, (int) windowFrame.bottom);
1134 }
1135
1136 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1137 Rect boundsInScreen) {
1138 WindowInfo window = WindowInfo.obtain();
1139 window.type = windowState.mAttrs.type;
1140 window.layer = windowState.mLayer;
1141 window.token = windowState.mClient.asBinder();
1142
1143 WindowState attachedWindow = windowState.mAttachedWindow;
1144 if (attachedWindow != null) {
1145 window.parentToken = attachedWindow.mClient.asBinder();
1146 }
1147
1148 window.focused = windowState.isFocused();
1149 window.boundsInScreen.set(boundsInScreen);
1150
1151 final int childCount = windowState.mChildWindows.size();
1152 if (childCount > 0) {
1153 if (window.childTokens == null) {
1154 window.childTokens = new ArrayList<IBinder>();
1155 }
1156 for (int j = 0; j < childCount; j++) {
1157 WindowState child = windowState.mChildWindows.get(j);
1158 window.childTokens.add(child.mClient.asBinder());
1159 }
1160 }
1161
1162 return window;
1163 }
1164
Svetoslav8e3feb12014-02-24 13:46:47 -08001165 private void cacheWindows(List<WindowInfo> windows) {
1166 final int oldWindowCount = mOldWindows.size();
1167 for (int i = oldWindowCount - 1; i >= 0; i--) {
1168 mOldWindows.remove(i).recycle();
1169 }
1170 final int newWindowCount = windows.size();
1171 for (int i = 0; i < newWindowCount; i++) {
1172 WindowInfo newWindow = windows.get(i);
1173 mOldWindows.add(WindowInfo.obtain(newWindow));
1174 }
1175 }
1176
1177 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1178 if (oldWindow == newWindow) {
1179 return false;
1180 }
Svetoslavf7174e82014-06-12 11:29:35 -07001181 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001182 return true;
1183 }
Svetoslavf7174e82014-06-12 11:29:35 -07001184 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001185 return true;
1186 }
1187 if (oldWindow.type != newWindow.type) {
1188 return true;
1189 }
1190 if (oldWindow.focused != newWindow.focused) {
1191 return true;
1192 }
1193 if (oldWindow.token == null) {
1194 if (newWindow.token != null) {
1195 return true;
1196 }
1197 } else if (!oldWindow.token.equals(newWindow.token)) {
1198 return true;
1199 }
1200 if (oldWindow.parentToken == null) {
1201 if (newWindow.parentToken != null) {
1202 return true;
1203 }
1204 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1205 return true;
1206 }
1207 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1208 return true;
1209 }
1210 if (oldWindow.childTokens != null && newWindow.childTokens != null
1211 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1212 return true;
1213 }
1214 return false;
1215 }
1216
1217 private void clearAndRecycleWindows(List<WindowInfo> windows) {
1218 final int windowCount = windows.size();
1219 for (int i = windowCount - 1; i >= 0; i--) {
1220 windows.remove(i).recycle();
1221 }
1222 }
1223
1224 private static boolean isReportedWindowType(int windowType) {
1225 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1226 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1227 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1228 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1229 && windowType != WindowManager.LayoutParams.TYPE_DRAG
1230 && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
1231 && windowType != WindowManager.LayoutParams.TYPE_POINTER
1232 && windowType != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
1233 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1234 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1235 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1236 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1237 }
1238
1239 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1240 DisplayContent displayContent = mWindowManagerService
1241 .getDefaultDisplayContentLocked();
1242 WindowList windowList = displayContent.getWindowList();
1243 final int windowCount = windowList.size();
1244 for (int i = 0; i < windowCount; i++) {
1245 WindowState windowState = windowList.get(i);
1246 if (windowState.isVisibleLw()) {
1247 outWindows.put(windowState.mLayer, windowState);
1248 }
1249 }
1250 }
1251
1252 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001253 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
1254 public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
Svetoslav8e3feb12014-02-24 13:46:47 -08001255
1256 public MyHandler(Looper looper) {
1257 super(looper, null, false);
1258 }
1259
1260 @Override
1261 @SuppressWarnings("unchecked")
1262 public void handleMessage(Message message) {
1263 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001264 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1265 computeChangedWindows();
1266 } break;
1267
Svetoslav8e3feb12014-02-24 13:46:47 -08001268 case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
1269 List<WindowInfo> windows = (List<WindowInfo>) message.obj;
1270 mCallback.onWindowsForAccessibilityChanged(windows);
1271 clearAndRecycleWindows(windows);
1272 } break;
1273 }
1274 }
1275 }
1276 }
1277}