blob: b501398c7d5738376ecb233ed9865ee2df9f4703 [file] [log] [blame]
Svetoslav8e3feb12014-02-24 13:46:47 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080019import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
21
Svetoslav8e3feb12014-02-24 13:46:47 -080022import android.animation.ObjectAnimator;
23import android.animation.ValueAnimator;
Alan Viverette59e53a12016-03-28 13:41:32 -040024import android.annotation.NonNull;
Svetoslav8e3feb12014-02-24 13:46:47 -080025import android.app.Service;
26import android.content.Context;
27import android.graphics.Canvas;
28import android.graphics.Color;
29import android.graphics.Matrix;
30import android.graphics.Paint;
31import android.graphics.Path;
32import android.graphics.PixelFormat;
33import android.graphics.Point;
34import android.graphics.PorterDuff.Mode;
35import android.graphics.Rect;
36import android.graphics.RectF;
37import android.graphics.Region;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Looper;
41import android.os.Message;
42import android.util.ArraySet;
43import android.util.Log;
44import android.util.Slog;
45import android.util.SparseArray;
46import android.util.TypedValue;
47import android.view.MagnificationSpec;
48import android.view.Surface;
49import android.view.Surface.OutOfResourcesException;
50import android.view.SurfaceControl;
Svetoslavf7174e82014-06-12 11:29:35 -070051import android.view.ViewConfiguration;
Svetoslav8e3feb12014-02-24 13:46:47 -080052import android.view.WindowInfo;
53import android.view.WindowManager;
54import android.view.WindowManagerInternal.MagnificationCallbacks;
55import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
56import android.view.WindowManagerPolicy;
57import android.view.animation.DecelerateInterpolator;
58import android.view.animation.Interpolator;
59
60import com.android.internal.R;
61import com.android.internal.os.SomeArgs;
62
63import java.util.ArrayList;
Allen Hairf20ac2c2016-02-11 17:42:59 -080064import java.util.HashSet;
Svetoslav8e3feb12014-02-24 13:46:47 -080065import java.util.List;
66import java.util.Set;
67
68/**
69 * This class contains the accessibility related logic of the window manger.
70 */
71final class AccessibilityController {
72
73 private final WindowManagerService mWindowManagerService;
74
75 private static final float[] sTempFloats = new float[9];
76
77 public AccessibilityController(WindowManagerService service) {
78 mWindowManagerService = service;
79 }
80
81 private DisplayMagnifier mDisplayMagnifier;
82
83 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
84
85 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
86 if (callbacks != null) {
87 if (mDisplayMagnifier != null) {
88 throw new IllegalStateException("Magnification callbacks already set!");
89 }
90 mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
91 } else {
92 if (mDisplayMagnifier == null) {
93 throw new IllegalStateException("Magnification callbacks already cleared!");
94 }
95 mDisplayMagnifier.destroyLocked();
96 mDisplayMagnifier = null;
97 }
98 }
99
100 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
101 if (callback != null) {
102 if (mWindowsForAccessibilityObserver != null) {
103 throw new IllegalStateException(
104 "Windows for accessibility callback already set!");
105 }
106 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
107 mWindowManagerService, callback);
108 } else {
109 if (mWindowsForAccessibilityObserver == null) {
110 throw new IllegalStateException(
111 "Windows for accessibility callback already cleared!");
112 }
113 mWindowsForAccessibilityObserver = null;
114 }
115 }
116
117 public void setMagnificationSpecLocked(MagnificationSpec spec) {
118 if (mDisplayMagnifier != null) {
119 mDisplayMagnifier.setMagnificationSpecLocked(spec);
120 }
121 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700122 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800123 }
124 }
125
Alan Viverette59e53a12016-03-28 13:41:32 -0400126 public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
127 if (mDisplayMagnifier != null) {
128 mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
129 }
130 }
131
Svetoslavf7174e82014-06-12 11:29:35 -0700132 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800133 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700134 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800135 }
136 // Not relevant for the window observer.
137 }
138
139 public void onWindowLayersChangedLocked() {
140 if (mDisplayMagnifier != null) {
141 mDisplayMagnifier.onWindowLayersChangedLocked();
142 }
143 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700144 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800145 }
146 }
147
148 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
149 if (mDisplayMagnifier != null) {
150 mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
151 }
152 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700153 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800154 }
155 }
156
157 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
158 if (mDisplayMagnifier != null) {
159 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
160 }
161 // Not relevant for the window observer.
162 }
163
164 public void onWindowTransitionLocked(WindowState windowState, int transition) {
165 if (mDisplayMagnifier != null) {
166 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
167 }
168 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700169 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800170 }
171 }
172
Svetoslav3a0d8782014-12-04 12:50:11 -0800173 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800174 // Not relevant for the display magnifier.
175
Svetoslav3a0d8782014-12-04 12:50:11 -0800176 WindowsForAccessibilityObserver observer = null;
177 synchronized (mWindowManagerService) {
178 observer = mWindowsForAccessibilityObserver;
179 }
180 if (observer != null) {
181 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800182 }
183 }
184
Svetoslav4604abc2014-06-10 18:59:30 -0700185
Svetoslavf7174e82014-06-12 11:29:35 -0700186 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700187 // Not relevant for the display magnifier.
188
189 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700190 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700191 }
192 }
193
Svetoslav8e3feb12014-02-24 13:46:47 -0800194 /** NOTE: This has to be called within a surface transaction. */
195 public void drawMagnifiedRegionBorderIfNeededLocked() {
196 if (mDisplayMagnifier != null) {
197 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
198 }
199 // Not relevant for the window observer.
200 }
201
202 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
203 if (mDisplayMagnifier != null) {
204 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
205 }
206 return null;
207 }
208
209 public boolean hasCallbacksLocked() {
210 return (mDisplayMagnifier != null
211 || mWindowsForAccessibilityObserver != null);
212 }
213
214 private static void populateTransformationMatrixLocked(WindowState windowState,
215 Matrix outMatrix) {
216 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
217 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
218 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
219 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
Filip Gruszczynski2a6a2c22015-10-14 12:00:53 -0700220 sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
221 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
Svetoslav8e3feb12014-02-24 13:46:47 -0800222 sTempFloats[Matrix.MPERSP_0] = 0;
223 sTempFloats[Matrix.MPERSP_1] = 0;
224 sTempFloats[Matrix.MPERSP_2] = 1;
225 outMatrix.setValues(sTempFloats);
226 }
227
228 /**
229 * This class encapsulates the functionality related to display magnification.
230 */
231 private static final class DisplayMagnifier {
232
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800233 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800234
235 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
236 private static final boolean DEBUG_ROTATION = false;
237 private static final boolean DEBUG_LAYERS = false;
238 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
239 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
240
241 private final Rect mTempRect1 = new Rect();
242 private final Rect mTempRect2 = new Rect();
243
244 private final Region mTempRegion1 = new Region();
245 private final Region mTempRegion2 = new Region();
246 private final Region mTempRegion3 = new Region();
247 private final Region mTempRegion4 = new Region();
248
249 private final Context mContext;
250 private final WindowManagerService mWindowManagerService;
251 private final MagnifiedViewport mMagnifedViewport;
252 private final Handler mHandler;
253
254 private final MagnificationCallbacks mCallbacks;
255
256 private final long mLongAnimationDuration;
257
258 public DisplayMagnifier(WindowManagerService windowManagerService,
259 MagnificationCallbacks callbacks) {
260 mContext = windowManagerService.mContext;
261 mWindowManagerService = windowManagerService;
262 mCallbacks = callbacks;
263 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
264 mMagnifedViewport = new MagnifiedViewport();
265 mLongAnimationDuration = mContext.getResources().getInteger(
266 com.android.internal.R.integer.config_longAnimTime);
267 }
268
269 public void setMagnificationSpecLocked(MagnificationSpec spec) {
270 mMagnifedViewport.updateMagnificationSpecLocked(spec);
271 mMagnifedViewport.recomputeBoundsLocked();
272 mWindowManagerService.scheduleAnimationLocked();
273 }
274
Svetoslavf7174e82014-06-12 11:29:35 -0700275 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800276 if (DEBUG_RECTANGLE_REQUESTED) {
277 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
278 }
279 if (!mMagnifedViewport.isMagnifyingLocked()) {
280 return;
281 }
282 Rect magnifiedRegionBounds = mTempRect2;
283 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
284 if (magnifiedRegionBounds.contains(rectangle)) {
285 return;
286 }
287 SomeArgs args = SomeArgs.obtain();
288 args.argi1 = rectangle.left;
289 args.argi2 = rectangle.top;
290 args.argi3 = rectangle.right;
291 args.argi4 = rectangle.bottom;
292 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
293 args).sendToTarget();
294 }
295
296 public void onWindowLayersChangedLocked() {
297 if (DEBUG_LAYERS) {
298 Slog.i(LOG_TAG, "Layers changed.");
299 }
300 mMagnifedViewport.recomputeBoundsLocked();
301 mWindowManagerService.scheduleAnimationLocked();
302 }
303
304 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
305 if (DEBUG_ROTATION) {
306 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
307 + " displayId: " + displayContent.getDisplayId());
308 }
309 mMagnifedViewport.onRotationChangedLocked();
310 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
311 }
312
313 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
314 if (DEBUG_WINDOW_TRANSITIONS) {
315 Slog.i(LOG_TAG, "Window transition: "
316 + AppTransition.appTransitionToString(transition)
317 + " displayId: " + windowState.getDisplayId());
318 }
319 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
320 if (magnifying) {
321 switch (transition) {
322 case AppTransition.TRANSIT_ACTIVITY_OPEN:
323 case AppTransition.TRANSIT_TASK_OPEN:
324 case AppTransition.TRANSIT_TASK_TO_FRONT:
325 case AppTransition.TRANSIT_WALLPAPER_OPEN:
326 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
327 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
328 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
329 }
330 }
331 }
332 }
333
334 public void onWindowTransitionLocked(WindowState windowState, int transition) {
335 if (DEBUG_WINDOW_TRANSITIONS) {
336 Slog.i(LOG_TAG, "Window transition: "
337 + AppTransition.appTransitionToString(transition)
338 + " displayId: " + windowState.getDisplayId());
339 }
340 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
341 final int type = windowState.mAttrs.type;
342 switch (transition) {
343 case WindowManagerPolicy.TRANSIT_ENTER:
344 case WindowManagerPolicy.TRANSIT_SHOW: {
345 if (!magnifying) {
346 break;
347 }
348 switch (type) {
349 case WindowManager.LayoutParams.TYPE_APPLICATION:
350 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
351 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
352 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700353 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800354 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
355 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
356 case WindowManager.LayoutParams.TYPE_PHONE:
357 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
358 case WindowManager.LayoutParams.TYPE_TOAST:
359 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
360 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
361 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
362 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
363 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
364 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500365 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200366 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800367 Rect magnifiedRegionBounds = mTempRect2;
368 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
369 magnifiedRegionBounds);
370 Rect touchableRegionBounds = mTempRect1;
371 windowState.getTouchableRegion(mTempRegion1);
372 mTempRegion1.getBounds(touchableRegionBounds);
373 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
374 mCallbacks.onRectangleOnScreenRequested(
375 touchableRegionBounds.left,
376 touchableRegionBounds.top,
377 touchableRegionBounds.right,
378 touchableRegionBounds.bottom);
379 }
380 } break;
381 } break;
382 }
383 }
384 }
385
386 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
387 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
388 if (spec != null && !spec.isNop()) {
389 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
390 final int windowType = windowState.mAttrs.type;
391 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
392 && !policy.canMagnifyWindow(windowType)) {
393 return null;
394 }
395 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
396 return null;
397 }
398 }
399 return spec;
400 }
401
Alan Viverette59e53a12016-03-28 13:41:32 -0400402 public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
403 mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
404 }
405
Svetoslav8e3feb12014-02-24 13:46:47 -0800406 public void destroyLocked() {
407 mMagnifedViewport.destroyWindow();
408 }
409
410 /** NOTE: This has to be called within a surface transaction. */
411 public void drawMagnifiedRegionBorderIfNeededLocked() {
412 mMagnifedViewport.drawWindowIfNeededLocked();
413 }
414
415 private final class MagnifiedViewport {
416
Svetoslav8e3feb12014-02-24 13:46:47 -0800417 private final SparseArray<WindowState> mTempWindowStates =
418 new SparseArray<WindowState>();
419
420 private final RectF mTempRectF = new RectF();
421
422 private final Point mTempPoint = new Point();
423
424 private final Matrix mTempMatrix = new Matrix();
425
426 private final Region mMagnifiedBounds = new Region();
Alan Viverette59e53a12016-03-28 13:41:32 -0400427 private final Region mAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800428 private final Region mOldMagnifiedBounds = new Region();
Alan Viverette214fb682015-11-17 09:47:11 -0500429 private final Region mOldAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800430
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800431 private final Path mCircularPath;
432
Svetoslav8e3feb12014-02-24 13:46:47 -0800433 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
434
435 private final WindowManager mWindowManager;
436
Svetoslav7505e332014-08-22 12:14:28 -0700437 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800438 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700439 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800440
441 private final ViewportWindow mWindow;
442
443 private boolean mFullRedrawNeeded;
444
445 public MagnifiedViewport() {
446 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800447 mBorderWidth = mContext.getResources().getDimension(
448 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700449 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
450 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800451 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800452
Adam Powell01f280d2015-05-18 16:07:42 -0700453 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800454 mCircularPath = new Path();
455 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
456 final int centerXY = mTempPoint.x / 2;
457 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
458 } else {
459 mCircularPath = null;
460 }
461
Svetoslav8e3feb12014-02-24 13:46:47 -0800462 recomputeBoundsLocked();
463 }
464
Alan Viverette59e53a12016-03-28 13:41:32 -0400465 public void getBoundsLocked(@NonNull Region outMagnified,
466 @NonNull Region outAvailable) {
467 outMagnified.set(mMagnifiedBounds);
468 outAvailable.set(mAvailableBounds);
469 }
470
Svetoslav8e3feb12014-02-24 13:46:47 -0800471 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
472 if (spec != null) {
473 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
474 } else {
475 mMagnificationSpec.clear();
476 }
477 // If this message is pending we are in a rotation animation and do not want
478 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700479 if (!mHandler.hasMessages(
480 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800481 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
482 }
483 }
484
485 public void recomputeBoundsLocked() {
486 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
487 final int screenWidth = mTempPoint.x;
488 final int screenHeight = mTempPoint.y;
489
Alan Viverette59e53a12016-03-28 13:41:32 -0400490 mMagnifiedBounds.set(0, 0, 0, 0);
491 mAvailableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800492
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800493 if (mCircularPath != null) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400494 mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800495 }
496
Svetoslav8e3feb12014-02-24 13:46:47 -0800497 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700498 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800499
500 SparseArray<WindowState> visibleWindows = mTempWindowStates;
501 visibleWindows.clear();
502 populateWindowsOnScreenLocked(visibleWindows);
503
504 final int visibleWindowCount = visibleWindows.size();
505 for (int i = visibleWindowCount - 1; i >= 0; i--) {
506 WindowState windowState = visibleWindows.valueAt(i);
507 if (windowState.mAttrs.type == WindowManager
508 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
509 continue;
510 }
511
Phil Weaver65c06702016-03-15 15:33:46 -0700512 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800513 Matrix matrix = mTempMatrix;
514 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700515 Region touchableRegion = mTempRegion3;
516 windowState.getTouchableRegion(touchableRegion);
517 Rect touchableFrame = mTempRect1;
518 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800519 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700520 windowFrame.set(touchableFrame);
521 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
522 matrix.mapRect(windowFrame);
523 Region windowBounds = mTempRegion2;
524 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
525 (int) windowFrame.right, (int) windowFrame.bottom);
526 // Only update new regions
527 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
528 portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
529 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
530 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800531
532 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400533 mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
534 mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800535 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800536 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Alan Viverette59e53a12016-03-28 13:41:32 -0400537 mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800538 }
539
Phil Weaver65c06702016-03-15 15:33:46 -0700540 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800541 Region accountedBounds = mTempRegion2;
Alan Viverette59e53a12016-03-28 13:41:32 -0400542 accountedBounds.set(mMagnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800543 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
544 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
545
546 if (accountedBounds.isRect()) {
547 Rect accountedFrame = mTempRect1;
548 accountedBounds.getBounds(accountedFrame);
549 if (accountedFrame.width() == screenWidth
550 && accountedFrame.height() == screenHeight) {
551 break;
552 }
553 }
554 }
555
556 visibleWindows.clear();
557
Alan Viverette59e53a12016-03-28 13:41:32 -0400558 mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700559 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800560 Region.Op.INTERSECT);
561
Alan Viverette59e53a12016-03-28 13:41:32 -0400562 final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
563 final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500564 if (magnifiedChanged || availableChanged) {
565 if (magnifiedChanged) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400566 mWindow.setBounds(mMagnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500567 Rect dirtyRect = mTempRect1;
568 if (mFullRedrawNeeded) {
569 mFullRedrawNeeded = false;
570 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
571 screenWidth - mDrawBorderInset,
572 screenHeight - mDrawBorderInset);
573 mWindow.invalidate(dirtyRect);
574 } else {
575 Region dirtyRegion = mTempRegion3;
Alan Viverette59e53a12016-03-28 13:41:32 -0400576 dirtyRegion.set(mMagnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500577 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
578 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
579 dirtyRegion.getBounds(dirtyRect);
580 mWindow.invalidate(dirtyRect);
581 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800582
Alan Viverette59e53a12016-03-28 13:41:32 -0400583 mOldMagnifiedBounds.set(mMagnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800584 }
585
Alan Viverette214fb682015-11-17 09:47:11 -0500586 if (availableChanged) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400587 mOldAvailableBounds.set(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500588 }
589
590 final SomeArgs args = SomeArgs.obtain();
Alan Viverette59e53a12016-03-28 13:41:32 -0400591 args.arg1 = Region.obtain(mMagnifiedBounds);
592 args.arg2 = Region.obtain(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500593 mHandler.obtainMessage(
594 MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800595 }
596 }
597
598 public void onRotationChangedLocked() {
599 // If we are magnifying, hide the magnified border window immediately so
600 // the user does not see strange artifacts during rotation. The screenshot
601 // used for rotation has already the border. After the rotation is complete
602 // we will show the border.
603 if (isMagnifyingLocked()) {
604 setMagnifiedRegionBorderShownLocked(false, false);
605 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700606 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800607 Message message = mHandler.obtainMessage(
608 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
609 mHandler.sendMessageDelayed(message, delay);
610 }
611 recomputeBoundsLocked();
612 mWindow.updateSize();
613 }
614
615 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
616 if (shown) {
617 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700618 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800619 }
620 mWindow.setShown(shown, animate);
621 }
622
623 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
624 MagnificationSpec spec = mMagnificationSpec;
625 mMagnifiedBounds.getBounds(rect);
626 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
627 rect.scale(1.0f / spec.scale);
628 }
629
630 public boolean isMagnifyingLocked() {
631 return mMagnificationSpec.scale > 1.0f;
632 }
633
634 public MagnificationSpec getMagnificationSpecLocked() {
635 return mMagnificationSpec;
636 }
637
638 /** NOTE: This has to be called within a surface transaction. */
639 public void drawWindowIfNeededLocked() {
640 recomputeBoundsLocked();
641 mWindow.drawIfNeeded();
642 }
643
644 public void destroyWindow() {
645 mWindow.releaseSurface();
646 }
647
648 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
649 DisplayContent displayContent = mWindowManagerService
650 .getDefaultDisplayContentLocked();
651 WindowList windowList = displayContent.getWindowList();
652 final int windowCount = windowList.size();
653 for (int i = 0; i < windowCount; i++) {
654 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800655 if (windowState.isOnScreen() &&
656 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800657 outWindows.put(windowState.mLayer, windowState);
658 }
659 }
660 }
661
662 private final class ViewportWindow {
663 private static final String SURFACE_TITLE = "Magnification Overlay";
664
Svetoslav8e3feb12014-02-24 13:46:47 -0800665 private final Region mBounds = new Region();
666 private final Rect mDirtyRect = new Rect();
667 private final Paint mPaint = new Paint();
668
Svetoslav8e3feb12014-02-24 13:46:47 -0800669 private final SurfaceControl mSurfaceControl;
670 private final Surface mSurface = new Surface();
671
Svet Ganovb21df802014-09-01 19:06:33 -0700672 private final AnimationController mAnimationController;
673
Svetoslav8e3feb12014-02-24 13:46:47 -0800674 private boolean mShown;
675 private int mAlpha;
676
677 private boolean mInvalidated;
678
679 public ViewportWindow(Context context) {
680 SurfaceControl surfaceControl = null;
681 try {
682 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
683 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
684 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
685 SurfaceControl.HIDDEN);
686 } catch (OutOfResourcesException oore) {
687 /* ignore */
688 }
689 mSurfaceControl = surfaceControl;
690 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
691 .getLayerStack());
692 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
693 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
694 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
695 mSurfaceControl.setPosition(0, 0);
696 mSurface.copyFrom(mSurfaceControl);
697
Svet Ganovb21df802014-09-01 19:06:33 -0700698 mAnimationController = new AnimationController(context,
699 mWindowManagerService.mH.getLooper());
700
Svetoslav8e3feb12014-02-24 13:46:47 -0800701 TypedValue typedValue = new TypedValue();
702 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
703 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700704 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800705
706 mPaint.setStyle(Paint.Style.STROKE);
707 mPaint.setStrokeWidth(mBorderWidth);
708 mPaint.setColor(borderColor);
709
Svetoslav8e3feb12014-02-24 13:46:47 -0800710 mInvalidated = true;
711 }
712
713 public void setShown(boolean shown, boolean animate) {
714 synchronized (mWindowManagerService.mWindowMap) {
715 if (mShown == shown) {
716 return;
717 }
718 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700719 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800720 if (DEBUG_VIEWPORT_WINDOW) {
721 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
722 }
723 }
724 }
725
726 @SuppressWarnings("unused")
727 // Called reflectively from an animator.
728 public int getAlpha() {
729 synchronized (mWindowManagerService.mWindowMap) {
730 return mAlpha;
731 }
732 }
733
734 public void setAlpha(int alpha) {
735 synchronized (mWindowManagerService.mWindowMap) {
736 if (mAlpha == alpha) {
737 return;
738 }
739 mAlpha = alpha;
740 invalidate(null);
741 if (DEBUG_VIEWPORT_WINDOW) {
742 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
743 }
744 }
745 }
746
747 public void setBounds(Region bounds) {
748 synchronized (mWindowManagerService.mWindowMap) {
749 if (mBounds.equals(bounds)) {
750 return;
751 }
752 mBounds.set(bounds);
753 invalidate(mDirtyRect);
754 if (DEBUG_VIEWPORT_WINDOW) {
755 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
756 }
757 }
758 }
759
760 public void updateSize() {
761 synchronized (mWindowManagerService.mWindowMap) {
762 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
763 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
764 invalidate(mDirtyRect);
765 }
766 }
767
768 public void invalidate(Rect dirtyRect) {
769 if (dirtyRect != null) {
770 mDirtyRect.set(dirtyRect);
771 } else {
772 mDirtyRect.setEmpty();
773 }
774 mInvalidated = true;
775 mWindowManagerService.scheduleAnimationLocked();
776 }
777
778 /** NOTE: This has to be called within a surface transaction. */
779 public void drawIfNeeded() {
780 synchronized (mWindowManagerService.mWindowMap) {
781 if (!mInvalidated) {
782 return;
783 }
784 mInvalidated = false;
785 Canvas canvas = null;
786 try {
787 // Empty dirty rectangle means unspecified.
788 if (mDirtyRect.isEmpty()) {
789 mBounds.getBounds(mDirtyRect);
790 }
791 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
792 canvas = mSurface.lockCanvas(mDirtyRect);
793 if (DEBUG_VIEWPORT_WINDOW) {
794 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
795 }
796 } catch (IllegalArgumentException iae) {
797 /* ignore */
798 } catch (Surface.OutOfResourcesException oore) {
799 /* ignore */
800 }
801 if (canvas == null) {
802 return;
803 }
804 if (DEBUG_VIEWPORT_WINDOW) {
805 Slog.i(LOG_TAG, "Bounds: " + mBounds);
806 }
807 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
808 mPaint.setAlpha(mAlpha);
809 Path path = mBounds.getBoundaryPath();
810 canvas.drawPath(path, mPaint);
811
812 mSurface.unlockCanvasAndPost(canvas);
813
814 if (mAlpha > 0) {
815 mSurfaceControl.show();
816 } else {
817 mSurfaceControl.hide();
818 }
819 }
820 }
821
822 public void releaseSurface() {
823 mSurfaceControl.release();
824 mSurface.release();
825 }
Svet Ganovb21df802014-09-01 19:06:33 -0700826
827 private final class AnimationController extends Handler {
828 private static final String PROPERTY_NAME_ALPHA = "alpha";
829
830 private static final int MIN_ALPHA = 0;
831 private static final int MAX_ALPHA = 255;
832
833 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
834
835 private final ValueAnimator mShowHideFrameAnimator;
836
837 public AnimationController(Context context, Looper looper) {
838 super(looper);
839 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
840 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
841
842 Interpolator interpolator = new DecelerateInterpolator(2.5f);
843 final long longAnimationDuration = context.getResources().getInteger(
844 com.android.internal.R.integer.config_longAnimTime);
845
846 mShowHideFrameAnimator.setInterpolator(interpolator);
847 mShowHideFrameAnimator.setDuration(longAnimationDuration);
848 }
849
850 public void onFrameShownStateChanged(boolean shown, boolean animate) {
851 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
852 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
853 }
854
855 @Override
856 public void handleMessage(Message message) {
857 switch (message.what) {
858 case MSG_FRAME_SHOWN_STATE_CHANGED: {
859 final boolean shown = message.arg1 == 1;
860 final boolean animate = message.arg2 == 1;
861
862 if (animate) {
863 if (mShowHideFrameAnimator.isRunning()) {
864 mShowHideFrameAnimator.reverse();
865 } else {
866 if (shown) {
867 mShowHideFrameAnimator.start();
868 } else {
869 mShowHideFrameAnimator.reverse();
870 }
871 }
872 } else {
873 mShowHideFrameAnimator.cancel();
874 if (shown) {
875 setAlpha(MAX_ALPHA);
876 } else {
877 setAlpha(MIN_ALPHA);
878 }
879 }
880 } break;
881 }
882 }
883 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800884 }
885 }
886
887 private class MyHandler extends Handler {
888 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
889 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
890 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
891 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
892 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
893
894 public MyHandler(Looper looper) {
895 super(looper);
896 }
897
898 @Override
899 public void handleMessage(Message message) {
900 switch (message.what) {
901 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500902 final SomeArgs args = (SomeArgs) message.obj;
903 final Region magnifiedBounds = (Region) args.arg1;
904 final Region availableBounds = (Region) args.arg2;
905 mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
906 magnifiedBounds.recycle();
907 availableBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800908 } break;
909
910 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
911 SomeArgs args = (SomeArgs) message.obj;
912 final int left = args.argi1;
913 final int top = args.argi2;
914 final int right = args.argi3;
915 final int bottom = args.argi4;
916 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
917 args.recycle();
918 } break;
919
920 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
921 mCallbacks.onUserContextChanged();
922 } break;
923
924 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
925 final int rotation = message.arg1;
926 mCallbacks.onRotationChanged(rotation);
927 } break;
928
929 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
930 synchronized (mWindowManagerService.mWindowMap) {
931 if (mMagnifedViewport.isMagnifyingLocked()) {
932 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
933 mWindowManagerService.scheduleAnimationLocked();
934 }
935 }
936 } break;
937 }
938 }
939 }
940 }
941
942 /**
943 * This class encapsulates the functionality related to computing the windows
944 * reported for accessibility purposes. These windows are all windows a sighted
945 * user can see on the screen.
946 */
947 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800948 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
949 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800950
951 private static final boolean DEBUG = false;
952
953 private final SparseArray<WindowState> mTempWindowStates =
954 new SparseArray<WindowState>();
955
956 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
957
958 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
959
960 private final RectF mTempRectF = new RectF();
961
962 private final Matrix mTempMatrix = new Matrix();
963
964 private final Point mTempPoint = new Point();
965
966 private final Rect mTempRect = new Rect();
967
968 private final Region mTempRegion = new Region();
969
970 private final Region mTempRegion1 = new Region();
971
972 private final Context mContext;
973
974 private final WindowManagerService mWindowManagerService;
975
976 private final Handler mHandler;
977
978 private final WindowsForAccessibilityCallback mCallback;
979
Svetoslavf7174e82014-06-12 11:29:35 -0700980 private final long mRecurringAccessibilityEventsIntervalMillis;
981
Svetoslav8e3feb12014-02-24 13:46:47 -0800982 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
983 WindowsForAccessibilityCallback callback) {
984 mContext = windowManagerService.mContext;
985 mWindowManagerService = windowManagerService;
986 mCallback = callback;
987 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700988 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
989 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800990 computeChangedWindows();
991 }
992
Svetoslav3a0d8782014-12-04 12:50:11 -0800993 public void performComputeChangedWindowsNotLocked() {
994 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
995 computeChangedWindows();
996 }
997
Svetoslavf7174e82014-06-12 11:29:35 -0700998 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800999 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001000 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1001 mRecurringAccessibilityEventsIntervalMillis);
1002 }
1003 }
1004
Svetoslav8e3feb12014-02-24 13:46:47 -08001005 public void computeChangedWindows() {
1006 if (DEBUG) {
1007 Slog.i(LOG_TAG, "computeChangedWindows()");
1008 }
1009
Svetoslav3a0d8782014-12-04 12:50:11 -08001010 boolean windowsChanged = false;
1011 List<WindowInfo> windows = new ArrayList<WindowInfo>();
1012
Svetoslav8e3feb12014-02-24 13:46:47 -08001013 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -07001014 // Do not send the windows if there is no current focus as
1015 // the window manager is still looking for where to put it.
1016 // We will do the work when we get a focus change callback.
1017 if (mWindowManagerService.mCurrentFocus == null) {
1018 return;
1019 }
1020
Svetoslav8e3feb12014-02-24 13:46:47 -08001021 WindowManager windowManager = (WindowManager)
1022 mContext.getSystemService(Context.WINDOW_SERVICE);
1023 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1024 final int screenWidth = mTempPoint.x;
1025 final int screenHeight = mTempPoint.y;
1026
1027 Region unaccountedSpace = mTempRegion;
1028 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1029
1030 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1031 populateVisibleWindowsOnScreenLocked(visibleWindows);
1032
Svetoslav8e3feb12014-02-24 13:46:47 -08001033 Set<IBinder> addedWindows = mTempBinderSet;
1034 addedWindows.clear();
1035
Svetoslavf7174e82014-06-12 11:29:35 -07001036 boolean focusedWindowAdded = false;
1037
Svetoslav8e3feb12014-02-24 13:46:47 -08001038 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001039 int skipRemainingWindowsForTaskId = -1;
1040 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001041 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001042 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001043 final int flags = windowState.mAttrs.flags;
Allen Hairf20ac2c2016-02-11 17:42:59 -08001044 final Task task = windowState.getTask();
1045
1046 // If the window is part of a task that we're finished with - ignore.
1047 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1048 continue;
1049 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001050
Svetoslav3a5c7212014-10-14 09:54:26 -07001051 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001052 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001053 continue;
1054 }
1055
Alan Viverette9538eea2014-11-13 14:49:20 -08001056 // Compute the bounds in the screen.
1057 final Rect boundsInScreen = mTempRect;
1058 computeWindowBoundsInScreen(windowState, boundsInScreen);
1059
Svetoslav8e3feb12014-02-24 13:46:47 -08001060 // If the window is completely covered by other windows - ignore.
1061 if (unaccountedSpace.quickReject(boundsInScreen)) {
1062 continue;
1063 }
1064
1065 // Add windows of certain types not covered by modal windows.
1066 if (isReportedWindowType(windowState.mAttrs.type)) {
1067 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001068 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001069 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001070 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001071 if (windowState.isFocused()) {
1072 focusedWindowAdded = true;
1073 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001074 }
1075
Alan Viveretted0c73f42014-11-18 10:25:04 -08001076 // Account for the space this window takes if the window
1077 // is not an accessibility overlay which does not change
1078 // the reported windows.
1079 if (windowState.mAttrs.type !=
1080 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1081 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1082 Region.Op.REVERSE_DIFFERENCE);
1083 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001084
1085 // We figured out what is touchable for the entire screen - done.
1086 if (unaccountedSpace.isEmpty()) {
1087 break;
1088 }
1089
Allen Hairf20ac2c2016-02-11 17:42:59 -08001090 // If a window is modal it prevents other windows from being touched
Svetoslav8e3feb12014-02-24 13:46:47 -08001091 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1092 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Allen Hairf20ac2c2016-02-11 17:42:59 -08001093 if (task != null) {
1094 // If the window is associated with a particular task, we can skip the
1095 // rest of the windows for that task.
1096 skipRemainingWindowsForTasks.add(task.mTaskId);
1097 continue;
1098 } else {
1099 // If the window is not associated with a particular task, then it is
1100 // globally modal. In this case we can skip all remaining windows.
1101 break;
1102 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001103 }
1104 }
1105
Svetoslavf7174e82014-06-12 11:29:35 -07001106 // Always report the focused window.
1107 if (!focusedWindowAdded) {
1108 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1109 WindowState windowState = visibleWindows.valueAt(i);
1110 if (windowState.isFocused()) {
1111 // Compute the bounds in the screen.
1112 Rect boundsInScreen = mTempRect;
1113 computeWindowBoundsInScreen(windowState, boundsInScreen);
1114
1115 // Add the window to the ones to be reported.
1116 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1117 boundsInScreen);
1118 addedWindows.add(window.token);
1119 windows.add(window);
1120 break;
1121 }
1122 }
1123 }
1124
Svetoslav8e3feb12014-02-24 13:46:47 -08001125 // Remove child/parent references to windows that were not added.
1126 final int windowCount = windows.size();
1127 for (int i = 0; i < windowCount; i++) {
1128 WindowInfo window = windows.get(i);
1129 if (!addedWindows.contains(window.parentToken)) {
1130 window.parentToken = null;
1131 }
1132 if (window.childTokens != null) {
1133 final int childTokenCount = window.childTokens.size();
1134 for (int j = childTokenCount - 1; j >= 0; j--) {
1135 if (!addedWindows.contains(window.childTokens.get(j))) {
1136 window.childTokens.remove(j);
1137 }
1138 }
1139 // Leave the child token list if empty.
1140 }
1141 }
1142
1143 visibleWindows.clear();
1144 addedWindows.clear();
1145
1146 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001147 if (mOldWindows.size() != windows.size()) {
1148 // Different size means something changed.
1149 windowsChanged = true;
1150 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1151 // Since we always traverse windows from high to low layer
1152 // the old and new windows at the same index should be the
1153 // same, otherwise something changed.
1154 for (int i = 0; i < windowCount; i++) {
1155 WindowInfo oldWindow = mOldWindows.get(i);
1156 WindowInfo newWindow = windows.get(i);
1157 // We do not care for layer changes given the window
1158 // order does not change. This brings no new information
1159 // to the clients.
1160 if (windowChangedNoLayer(oldWindow, newWindow)) {
1161 windowsChanged = true;
1162 break;
1163 }
1164 }
1165 }
1166
1167 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001168 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001169 }
1170 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001171
1172 // Now we do not hold the lock, so send the windows over.
1173 if (windowsChanged) {
1174 if (DEBUG) {
1175 Log.i(LOG_TAG, "Windows changed:" + windows);
1176 }
1177 mCallback.onWindowsForAccessibilityChanged(windows);
1178 } else {
1179 if (DEBUG) {
1180 Log.i(LOG_TAG, "No windows changed.");
1181 }
1182 }
1183
1184 // Recycle the windows as we do not need them.
1185 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001186 }
1187
Svetoslavf7174e82014-06-12 11:29:35 -07001188 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1189 // Get the touchable frame.
1190 Region touchableRegion = mTempRegion1;
1191 windowState.getTouchableRegion(touchableRegion);
1192 Rect touchableFrame = mTempRect;
1193 touchableRegion.getBounds(touchableFrame);
1194
1195 // Move to origin as all transforms are captured by the matrix.
1196 RectF windowFrame = mTempRectF;
1197 windowFrame.set(touchableFrame);
1198 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1199
1200 // Map the frame to get what appears on the screen.
1201 Matrix matrix = mTempMatrix;
1202 populateTransformationMatrixLocked(windowState, matrix);
1203 matrix.mapRect(windowFrame);
1204
1205 // Got the bounds.
1206 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1207 (int) windowFrame.right, (int) windowFrame.bottom);
1208 }
1209
1210 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1211 Rect boundsInScreen) {
1212 WindowInfo window = WindowInfo.obtain();
1213 window.type = windowState.mAttrs.type;
1214 window.layer = windowState.mLayer;
1215 window.token = windowState.mClient.asBinder();
1216
1217 WindowState attachedWindow = windowState.mAttachedWindow;
1218 if (attachedWindow != null) {
1219 window.parentToken = attachedWindow.mClient.asBinder();
1220 }
1221
1222 window.focused = windowState.isFocused();
1223 window.boundsInScreen.set(boundsInScreen);
1224
1225 final int childCount = windowState.mChildWindows.size();
1226 if (childCount > 0) {
1227 if (window.childTokens == null) {
1228 window.childTokens = new ArrayList<IBinder>();
1229 }
1230 for (int j = 0; j < childCount; j++) {
1231 WindowState child = windowState.mChildWindows.get(j);
1232 window.childTokens.add(child.mClient.asBinder());
1233 }
1234 }
1235
1236 return window;
1237 }
1238
Svetoslav8e3feb12014-02-24 13:46:47 -08001239 private void cacheWindows(List<WindowInfo> windows) {
1240 final int oldWindowCount = mOldWindows.size();
1241 for (int i = oldWindowCount - 1; i >= 0; i--) {
1242 mOldWindows.remove(i).recycle();
1243 }
1244 final int newWindowCount = windows.size();
1245 for (int i = 0; i < newWindowCount; i++) {
1246 WindowInfo newWindow = windows.get(i);
1247 mOldWindows.add(WindowInfo.obtain(newWindow));
1248 }
1249 }
1250
1251 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1252 if (oldWindow == newWindow) {
1253 return false;
1254 }
Svetoslavf7174e82014-06-12 11:29:35 -07001255 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001256 return true;
1257 }
Svetoslavf7174e82014-06-12 11:29:35 -07001258 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001259 return true;
1260 }
1261 if (oldWindow.type != newWindow.type) {
1262 return true;
1263 }
1264 if (oldWindow.focused != newWindow.focused) {
1265 return true;
1266 }
1267 if (oldWindow.token == null) {
1268 if (newWindow.token != null) {
1269 return true;
1270 }
1271 } else if (!oldWindow.token.equals(newWindow.token)) {
1272 return true;
1273 }
1274 if (oldWindow.parentToken == null) {
1275 if (newWindow.parentToken != null) {
1276 return true;
1277 }
1278 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1279 return true;
1280 }
1281 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1282 return true;
1283 }
1284 if (oldWindow.childTokens != null && newWindow.childTokens != null
1285 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1286 return true;
1287 }
1288 return false;
1289 }
1290
Svetoslav3a0d8782014-12-04 12:50:11 -08001291 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001292 final int windowCount = windows.size();
1293 for (int i = windowCount - 1; i >= 0; i--) {
1294 windows.remove(i).recycle();
1295 }
1296 }
1297
1298 private static boolean isReportedWindowType(int windowType) {
1299 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1300 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1301 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1302 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1303 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001304 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001305 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Svetoslav8e3feb12014-02-24 13:46:47 -08001306 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1307 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1308 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1309 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1310 }
1311
1312 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1313 DisplayContent displayContent = mWindowManagerService
1314 .getDefaultDisplayContentLocked();
1315 WindowList windowList = displayContent.getWindowList();
1316 final int windowCount = windowList.size();
1317 for (int i = 0; i < windowCount; i++) {
1318 WindowState windowState = windowList.get(i);
1319 if (windowState.isVisibleLw()) {
1320 outWindows.put(windowState.mLayer, windowState);
1321 }
1322 }
1323 }
1324
1325 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001326 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001327
1328 public MyHandler(Looper looper) {
1329 super(looper, null, false);
1330 }
1331
1332 @Override
1333 @SuppressWarnings("unchecked")
1334 public void handleMessage(Message message) {
1335 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001336 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1337 computeChangedWindows();
1338 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001339 }
1340 }
1341 }
1342 }
1343}