blob: 101f56f49241fe974e0bd5392de6bb2f2a073d1d [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;
Phil Weaver396d5492016-03-22 17:53:50 -070042import android.text.TextUtils;
Svetoslav8e3feb12014-02-24 13:46:47 -080043import android.util.ArraySet;
44import android.util.Log;
45import android.util.Slog;
46import android.util.SparseArray;
47import android.util.TypedValue;
48import android.view.MagnificationSpec;
49import android.view.Surface;
50import android.view.Surface.OutOfResourcesException;
51import android.view.SurfaceControl;
Svetoslavf7174e82014-06-12 11:29:35 -070052import android.view.ViewConfiguration;
Svetoslav8e3feb12014-02-24 13:46:47 -080053import android.view.WindowInfo;
54import android.view.WindowManager;
55import android.view.WindowManagerInternal.MagnificationCallbacks;
56import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
57import android.view.WindowManagerPolicy;
58import android.view.animation.DecelerateInterpolator;
59import android.view.animation.Interpolator;
60
61import com.android.internal.R;
62import com.android.internal.os.SomeArgs;
63
64import java.util.ArrayList;
Allen Hairf20ac2c2016-02-11 17:42:59 -080065import java.util.HashSet;
Svetoslav8e3feb12014-02-24 13:46:47 -080066import java.util.List;
67import java.util.Set;
68
69/**
70 * This class contains the accessibility related logic of the window manger.
71 */
72final class AccessibilityController {
73
74 private final WindowManagerService mWindowManagerService;
75
76 private static final float[] sTempFloats = new float[9];
77
78 public AccessibilityController(WindowManagerService service) {
79 mWindowManagerService = service;
80 }
81
82 private DisplayMagnifier mDisplayMagnifier;
83
84 private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
85
86 public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
87 if (callbacks != null) {
88 if (mDisplayMagnifier != null) {
89 throw new IllegalStateException("Magnification callbacks already set!");
90 }
91 mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
92 } else {
93 if (mDisplayMagnifier == null) {
94 throw new IllegalStateException("Magnification callbacks already cleared!");
95 }
96 mDisplayMagnifier.destroyLocked();
97 mDisplayMagnifier = null;
98 }
99 }
100
101 public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
102 if (callback != null) {
103 if (mWindowsForAccessibilityObserver != null) {
104 throw new IllegalStateException(
105 "Windows for accessibility callback already set!");
106 }
107 mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
108 mWindowManagerService, callback);
109 } else {
110 if (mWindowsForAccessibilityObserver == null) {
111 throw new IllegalStateException(
112 "Windows for accessibility callback already cleared!");
113 }
114 mWindowsForAccessibilityObserver = null;
115 }
116 }
117
118 public void setMagnificationSpecLocked(MagnificationSpec spec) {
119 if (mDisplayMagnifier != null) {
120 mDisplayMagnifier.setMagnificationSpecLocked(spec);
121 }
122 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700123 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800124 }
125 }
126
Phil Weaver70439242016-03-10 15:15:49 -0800127 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400128 if (mDisplayMagnifier != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800129 mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400130 }
131 }
132
Svetoslavf7174e82014-06-12 11:29:35 -0700133 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800134 if (mDisplayMagnifier != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700135 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
Svetoslav8e3feb12014-02-24 13:46:47 -0800136 }
137 // Not relevant for the window observer.
138 }
139
140 public void onWindowLayersChangedLocked() {
141 if (mDisplayMagnifier != null) {
142 mDisplayMagnifier.onWindowLayersChangedLocked();
143 }
144 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700145 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800146 }
147 }
148
149 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
150 if (mDisplayMagnifier != null) {
151 mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
152 }
153 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700154 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800155 }
156 }
157
158 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
159 if (mDisplayMagnifier != null) {
160 mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
161 }
162 // Not relevant for the window observer.
163 }
164
165 public void onWindowTransitionLocked(WindowState windowState, int transition) {
166 if (mDisplayMagnifier != null) {
167 mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
168 }
169 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700170 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800171 }
172 }
173
Svetoslav3a0d8782014-12-04 12:50:11 -0800174 public void onWindowFocusChangedNotLocked() {
Svetoslav8e3feb12014-02-24 13:46:47 -0800175 // Not relevant for the display magnifier.
176
Svetoslav3a0d8782014-12-04 12:50:11 -0800177 WindowsForAccessibilityObserver observer = null;
178 synchronized (mWindowManagerService) {
179 observer = mWindowsForAccessibilityObserver;
180 }
181 if (observer != null) {
182 observer.performComputeChangedWindowsNotLocked();
Svetoslav8e3feb12014-02-24 13:46:47 -0800183 }
184 }
185
Svetoslav4604abc2014-06-10 18:59:30 -0700186
Svetoslavf7174e82014-06-12 11:29:35 -0700187 public void onSomeWindowResizedOrMovedLocked() {
Svetoslav4604abc2014-06-10 18:59:30 -0700188 // Not relevant for the display magnifier.
189
190 if (mWindowsForAccessibilityObserver != null) {
Svetoslavf7174e82014-06-12 11:29:35 -0700191 mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
Svetoslav4604abc2014-06-10 18:59:30 -0700192 }
193 }
194
Svetoslav8e3feb12014-02-24 13:46:47 -0800195 /** NOTE: This has to be called within a surface transaction. */
196 public void drawMagnifiedRegionBorderIfNeededLocked() {
197 if (mDisplayMagnifier != null) {
198 mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
199 }
200 // Not relevant for the window observer.
201 }
202
203 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
204 if (mDisplayMagnifier != null) {
205 return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
206 }
207 return null;
208 }
209
210 public boolean hasCallbacksLocked() {
211 return (mDisplayMagnifier != null
212 || mWindowsForAccessibilityObserver != null);
213 }
214
215 private static void populateTransformationMatrixLocked(WindowState windowState,
216 Matrix outMatrix) {
217 sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
218 sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
219 sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
220 sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
Filip Gruszczynski2a6a2c22015-10-14 12:00:53 -0700221 sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
222 sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
Svetoslav8e3feb12014-02-24 13:46:47 -0800223 sTempFloats[Matrix.MPERSP_0] = 0;
224 sTempFloats[Matrix.MPERSP_1] = 0;
225 sTempFloats[Matrix.MPERSP_2] = 1;
226 outMatrix.setValues(sTempFloats);
227 }
228
229 /**
230 * This class encapsulates the functionality related to display magnification.
231 */
232 private static final class DisplayMagnifier {
233
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800234 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800235
236 private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
237 private static final boolean DEBUG_ROTATION = false;
238 private static final boolean DEBUG_LAYERS = false;
239 private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
240 private static final boolean DEBUG_VIEWPORT_WINDOW = false;
241
242 private final Rect mTempRect1 = new Rect();
243 private final Rect mTempRect2 = new Rect();
244
245 private final Region mTempRegion1 = new Region();
246 private final Region mTempRegion2 = new Region();
247 private final Region mTempRegion3 = new Region();
248 private final Region mTempRegion4 = new Region();
249
250 private final Context mContext;
251 private final WindowManagerService mWindowManagerService;
252 private final MagnifiedViewport mMagnifedViewport;
253 private final Handler mHandler;
254
255 private final MagnificationCallbacks mCallbacks;
256
257 private final long mLongAnimationDuration;
258
259 public DisplayMagnifier(WindowManagerService windowManagerService,
260 MagnificationCallbacks callbacks) {
261 mContext = windowManagerService.mContext;
262 mWindowManagerService = windowManagerService;
263 mCallbacks = callbacks;
264 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
265 mMagnifedViewport = new MagnifiedViewport();
266 mLongAnimationDuration = mContext.getResources().getInteger(
267 com.android.internal.R.integer.config_longAnimTime);
268 }
269
270 public void setMagnificationSpecLocked(MagnificationSpec spec) {
271 mMagnifedViewport.updateMagnificationSpecLocked(spec);
272 mMagnifedViewport.recomputeBoundsLocked();
273 mWindowManagerService.scheduleAnimationLocked();
274 }
275
Svetoslavf7174e82014-06-12 11:29:35 -0700276 public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800277 if (DEBUG_RECTANGLE_REQUESTED) {
278 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
279 }
280 if (!mMagnifedViewport.isMagnifyingLocked()) {
281 return;
282 }
283 Rect magnifiedRegionBounds = mTempRect2;
284 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
285 if (magnifiedRegionBounds.contains(rectangle)) {
286 return;
287 }
288 SomeArgs args = SomeArgs.obtain();
289 args.argi1 = rectangle.left;
290 args.argi2 = rectangle.top;
291 args.argi3 = rectangle.right;
292 args.argi4 = rectangle.bottom;
293 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
294 args).sendToTarget();
295 }
296
297 public void onWindowLayersChangedLocked() {
298 if (DEBUG_LAYERS) {
299 Slog.i(LOG_TAG, "Layers changed.");
300 }
301 mMagnifedViewport.recomputeBoundsLocked();
302 mWindowManagerService.scheduleAnimationLocked();
303 }
304
305 public void onRotationChangedLocked(DisplayContent displayContent, int rotation) {
306 if (DEBUG_ROTATION) {
307 Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation)
308 + " displayId: " + displayContent.getDisplayId());
309 }
310 mMagnifedViewport.onRotationChangedLocked();
311 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
312 }
313
314 public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
315 if (DEBUG_WINDOW_TRANSITIONS) {
316 Slog.i(LOG_TAG, "Window transition: "
317 + AppTransition.appTransitionToString(transition)
318 + " displayId: " + windowState.getDisplayId());
319 }
320 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
321 if (magnifying) {
322 switch (transition) {
323 case AppTransition.TRANSIT_ACTIVITY_OPEN:
324 case AppTransition.TRANSIT_TASK_OPEN:
325 case AppTransition.TRANSIT_TASK_TO_FRONT:
326 case AppTransition.TRANSIT_WALLPAPER_OPEN:
327 case AppTransition.TRANSIT_WALLPAPER_CLOSE:
328 case AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN: {
329 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
330 }
331 }
332 }
333 }
334
335 public void onWindowTransitionLocked(WindowState windowState, int transition) {
336 if (DEBUG_WINDOW_TRANSITIONS) {
337 Slog.i(LOG_TAG, "Window transition: "
338 + AppTransition.appTransitionToString(transition)
339 + " displayId: " + windowState.getDisplayId());
340 }
341 final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
342 final int type = windowState.mAttrs.type;
343 switch (transition) {
344 case WindowManagerPolicy.TRANSIT_ENTER:
345 case WindowManagerPolicy.TRANSIT_SHOW: {
346 if (!magnifying) {
347 break;
348 }
349 switch (type) {
350 case WindowManager.LayoutParams.TYPE_APPLICATION:
351 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
352 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
353 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
Wale Ogunwale0a4dc222015-04-14 12:58:42 -0700354 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
Svetoslav8e3feb12014-02-24 13:46:47 -0800355 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
356 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
357 case WindowManager.LayoutParams.TYPE_PHONE:
358 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
359 case WindowManager.LayoutParams.TYPE_TOAST:
360 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
361 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
362 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
363 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
364 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
365 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
Jason Monk8f7f3182015-11-18 16:35:14 -0500366 case WindowManager.LayoutParams.TYPE_QS_DIALOG:
Adrian Roos9a645132014-10-08 02:59:56 +0200367 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Svetoslav8e3feb12014-02-24 13:46:47 -0800368 Rect magnifiedRegionBounds = mTempRect2;
369 mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
370 magnifiedRegionBounds);
371 Rect touchableRegionBounds = mTempRect1;
372 windowState.getTouchableRegion(mTempRegion1);
373 mTempRegion1.getBounds(touchableRegionBounds);
374 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
375 mCallbacks.onRectangleOnScreenRequested(
376 touchableRegionBounds.left,
377 touchableRegionBounds.top,
378 touchableRegionBounds.right,
379 touchableRegionBounds.bottom);
380 }
381 } break;
382 } break;
383 }
384 }
385 }
386
387 public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
388 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
389 if (spec != null && !spec.isNop()) {
390 WindowManagerPolicy policy = mWindowManagerService.mPolicy;
391 final int windowType = windowState.mAttrs.type;
392 if (!policy.isTopLevelWindow(windowType) && windowState.mAttachedWindow != null
393 && !policy.canMagnifyWindow(windowType)) {
394 return null;
395 }
396 if (!policy.canMagnifyWindow(windowState.mAttrs.type)) {
397 return null;
398 }
399 }
400 return spec;
401 }
402
Phil Weaver70439242016-03-10 15:15:49 -0800403 public void getMagnificationRegionLocked(Region outMagnificationRegion) {
404 mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400405 }
406
Svetoslav8e3feb12014-02-24 13:46:47 -0800407 public void destroyLocked() {
408 mMagnifedViewport.destroyWindow();
409 }
410
411 /** NOTE: This has to be called within a surface transaction. */
412 public void drawMagnifiedRegionBorderIfNeededLocked() {
413 mMagnifedViewport.drawWindowIfNeededLocked();
414 }
415
416 private final class MagnifiedViewport {
417
Svetoslav8e3feb12014-02-24 13:46:47 -0800418 private final SparseArray<WindowState> mTempWindowStates =
419 new SparseArray<WindowState>();
420
421 private final RectF mTempRectF = new RectF();
422
423 private final Point mTempPoint = new Point();
424
425 private final Matrix mTempMatrix = new Matrix();
426
Phil Weaver70439242016-03-10 15:15:49 -0800427 private final Region mMagnificationRegion = new Region();
428 private final Region mOldMagnificationRegion = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800429
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800430 private final Path mCircularPath;
431
Svetoslav8e3feb12014-02-24 13:46:47 -0800432 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
433
434 private final WindowManager mWindowManager;
435
Svetoslav7505e332014-08-22 12:14:28 -0700436 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800437 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700438 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800439
440 private final ViewportWindow mWindow;
441
442 private boolean mFullRedrawNeeded;
443
444 public MagnifiedViewport() {
445 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800446 mBorderWidth = mContext.getResources().getDimension(
447 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700448 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
449 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800450 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800451
Adam Powell01f280d2015-05-18 16:07:42 -0700452 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800453 mCircularPath = new Path();
454 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
455 final int centerXY = mTempPoint.x / 2;
456 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
457 } else {
458 mCircularPath = null;
459 }
460
Svetoslav8e3feb12014-02-24 13:46:47 -0800461 recomputeBoundsLocked();
462 }
463
Phil Weaver70439242016-03-10 15:15:49 -0800464 public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
465 outMagnificationRegion.set(mMagnificationRegion);
Alan Viverette59e53a12016-03-28 13:41:32 -0400466 }
467
Svetoslav8e3feb12014-02-24 13:46:47 -0800468 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
469 if (spec != null) {
470 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
471 } else {
472 mMagnificationSpec.clear();
473 }
474 // If this message is pending we are in a rotation animation and do not want
475 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700476 if (!mHandler.hasMessages(
477 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800478 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
479 }
480 }
481
482 public void recomputeBoundsLocked() {
483 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
484 final int screenWidth = mTempPoint.x;
485 final int screenHeight = mTempPoint.y;
486
Phil Weaver70439242016-03-10 15:15:49 -0800487 mMagnificationRegion.set(0, 0, 0, 0);
488 final Region availableBounds = mTempRegion1;
489 availableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800490
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800491 if (mCircularPath != null) {
Phil Weaver70439242016-03-10 15:15:49 -0800492 availableBounds.setPath(mCircularPath, availableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800493 }
494
Svetoslav8e3feb12014-02-24 13:46:47 -0800495 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700496 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800497
498 SparseArray<WindowState> visibleWindows = mTempWindowStates;
499 visibleWindows.clear();
500 populateWindowsOnScreenLocked(visibleWindows);
501
502 final int visibleWindowCount = visibleWindows.size();
503 for (int i = visibleWindowCount - 1; i >= 0; i--) {
504 WindowState windowState = visibleWindows.valueAt(i);
505 if (windowState.mAttrs.type == WindowManager
506 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
507 continue;
508 }
509
Phil Weaver65c06702016-03-15 15:33:46 -0700510 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800511 Matrix matrix = mTempMatrix;
512 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700513 Region touchableRegion = mTempRegion3;
514 windowState.getTouchableRegion(touchableRegion);
515 Rect touchableFrame = mTempRect1;
516 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800517 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700518 windowFrame.set(touchableFrame);
519 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
520 matrix.mapRect(windowFrame);
521 Region windowBounds = mTempRegion2;
522 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
523 (int) windowFrame.right, (int) windowFrame.bottom);
524 // Only update new regions
525 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
Phil Weaver70439242016-03-10 15:15:49 -0800526 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
Phil Weaver65c06702016-03-15 15:33:46 -0700527 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
528 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800529
530 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
Phil Weaver70439242016-03-10 15:15:49 -0800531 mMagnificationRegion.op(windowBounds, Region.Op.UNION);
532 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800533 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800534 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Phil Weaver70439242016-03-10 15:15:49 -0800535 availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800536 }
537
Phil Weaver65c06702016-03-15 15:33:46 -0700538 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800539 Region accountedBounds = mTempRegion2;
Phil Weaver70439242016-03-10 15:15:49 -0800540 accountedBounds.set(mMagnificationRegion);
Svetoslav8e3feb12014-02-24 13:46:47 -0800541 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
542 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
543
544 if (accountedBounds.isRect()) {
545 Rect accountedFrame = mTempRect1;
546 accountedBounds.getBounds(accountedFrame);
547 if (accountedFrame.width() == screenWidth
548 && accountedFrame.height() == screenHeight) {
549 break;
550 }
551 }
552 }
553
554 visibleWindows.clear();
555
Phil Weaver70439242016-03-10 15:15:49 -0800556 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700557 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800558 Region.Op.INTERSECT);
559
Phil Weaver70439242016-03-10 15:15:49 -0800560 final boolean magnifiedChanged =
561 !mOldMagnificationRegion.equals(mMagnificationRegion);
562 if (magnifiedChanged) {
563 mWindow.setBounds(mMagnificationRegion);
564 final Rect dirtyRect = mTempRect1;
565 if (mFullRedrawNeeded) {
566 mFullRedrawNeeded = false;
567 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
568 screenWidth - mDrawBorderInset,
569 screenHeight - mDrawBorderInset);
570 mWindow.invalidate(dirtyRect);
571 } else {
572 final Region dirtyRegion = mTempRegion3;
573 dirtyRegion.set(mMagnificationRegion);
574 dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
575 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
576 dirtyRegion.getBounds(dirtyRect);
577 mWindow.invalidate(dirtyRect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800578 }
579
Phil Weaver70439242016-03-10 15:15:49 -0800580 mOldMagnificationRegion.set(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500581 final SomeArgs args = SomeArgs.obtain();
Phil Weaver70439242016-03-10 15:15:49 -0800582 args.arg1 = Region.obtain(mMagnificationRegion);
Alan Viverette214fb682015-11-17 09:47:11 -0500583 mHandler.obtainMessage(
Phil Weaver70439242016-03-10 15:15:49 -0800584 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
585 .sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800586 }
587 }
588
589 public void onRotationChangedLocked() {
590 // If we are magnifying, hide the magnified border window immediately so
591 // the user does not see strange artifacts during rotation. The screenshot
592 // used for rotation has already the border. After the rotation is complete
593 // we will show the border.
594 if (isMagnifyingLocked()) {
595 setMagnifiedRegionBorderShownLocked(false, false);
596 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700597 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800598 Message message = mHandler.obtainMessage(
599 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
600 mHandler.sendMessageDelayed(message, delay);
601 }
602 recomputeBoundsLocked();
603 mWindow.updateSize();
604 }
605
606 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
607 if (shown) {
608 mFullRedrawNeeded = true;
Phil Weaver70439242016-03-10 15:15:49 -0800609 mOldMagnificationRegion.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800610 }
611 mWindow.setShown(shown, animate);
612 }
613
614 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
615 MagnificationSpec spec = mMagnificationSpec;
Phil Weaver70439242016-03-10 15:15:49 -0800616 mMagnificationRegion.getBounds(rect);
Svetoslav8e3feb12014-02-24 13:46:47 -0800617 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
618 rect.scale(1.0f / spec.scale);
619 }
620
621 public boolean isMagnifyingLocked() {
622 return mMagnificationSpec.scale > 1.0f;
623 }
624
625 public MagnificationSpec getMagnificationSpecLocked() {
626 return mMagnificationSpec;
627 }
628
629 /** NOTE: This has to be called within a surface transaction. */
630 public void drawWindowIfNeededLocked() {
631 recomputeBoundsLocked();
632 mWindow.drawIfNeeded();
633 }
634
635 public void destroyWindow() {
636 mWindow.releaseSurface();
637 }
638
639 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
640 DisplayContent displayContent = mWindowManagerService
641 .getDefaultDisplayContentLocked();
642 WindowList windowList = displayContent.getWindowList();
643 final int windowCount = windowList.size();
644 for (int i = 0; i < windowCount; i++) {
645 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800646 if (windowState.isOnScreen() &&
647 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800648 outWindows.put(windowState.mLayer, windowState);
649 }
650 }
651 }
652
653 private final class ViewportWindow {
654 private static final String SURFACE_TITLE = "Magnification Overlay";
655
Svetoslav8e3feb12014-02-24 13:46:47 -0800656 private final Region mBounds = new Region();
657 private final Rect mDirtyRect = new Rect();
658 private final Paint mPaint = new Paint();
659
Svetoslav8e3feb12014-02-24 13:46:47 -0800660 private final SurfaceControl mSurfaceControl;
661 private final Surface mSurface = new Surface();
662
Svet Ganovb21df802014-09-01 19:06:33 -0700663 private final AnimationController mAnimationController;
664
Svetoslav8e3feb12014-02-24 13:46:47 -0800665 private boolean mShown;
666 private int mAlpha;
667
668 private boolean mInvalidated;
669
670 public ViewportWindow(Context context) {
671 SurfaceControl surfaceControl = null;
672 try {
673 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
674 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
675 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
676 SurfaceControl.HIDDEN);
677 } catch (OutOfResourcesException oore) {
678 /* ignore */
679 }
680 mSurfaceControl = surfaceControl;
681 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
682 .getLayerStack());
683 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
684 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
685 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
686 mSurfaceControl.setPosition(0, 0);
687 mSurface.copyFrom(mSurfaceControl);
688
Svet Ganovb21df802014-09-01 19:06:33 -0700689 mAnimationController = new AnimationController(context,
690 mWindowManagerService.mH.getLooper());
691
Svetoslav8e3feb12014-02-24 13:46:47 -0800692 TypedValue typedValue = new TypedValue();
693 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
694 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700695 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800696
697 mPaint.setStyle(Paint.Style.STROKE);
698 mPaint.setStrokeWidth(mBorderWidth);
699 mPaint.setColor(borderColor);
700
Svetoslav8e3feb12014-02-24 13:46:47 -0800701 mInvalidated = true;
702 }
703
704 public void setShown(boolean shown, boolean animate) {
705 synchronized (mWindowManagerService.mWindowMap) {
706 if (mShown == shown) {
707 return;
708 }
709 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700710 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800711 if (DEBUG_VIEWPORT_WINDOW) {
712 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
713 }
714 }
715 }
716
717 @SuppressWarnings("unused")
718 // Called reflectively from an animator.
719 public int getAlpha() {
720 synchronized (mWindowManagerService.mWindowMap) {
721 return mAlpha;
722 }
723 }
724
725 public void setAlpha(int alpha) {
726 synchronized (mWindowManagerService.mWindowMap) {
727 if (mAlpha == alpha) {
728 return;
729 }
730 mAlpha = alpha;
731 invalidate(null);
732 if (DEBUG_VIEWPORT_WINDOW) {
733 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
734 }
735 }
736 }
737
738 public void setBounds(Region bounds) {
739 synchronized (mWindowManagerService.mWindowMap) {
740 if (mBounds.equals(bounds)) {
741 return;
742 }
743 mBounds.set(bounds);
744 invalidate(mDirtyRect);
745 if (DEBUG_VIEWPORT_WINDOW) {
746 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
747 }
748 }
749 }
750
751 public void updateSize() {
752 synchronized (mWindowManagerService.mWindowMap) {
753 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
754 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
755 invalidate(mDirtyRect);
756 }
757 }
758
759 public void invalidate(Rect dirtyRect) {
760 if (dirtyRect != null) {
761 mDirtyRect.set(dirtyRect);
762 } else {
763 mDirtyRect.setEmpty();
764 }
765 mInvalidated = true;
766 mWindowManagerService.scheduleAnimationLocked();
767 }
768
769 /** NOTE: This has to be called within a surface transaction. */
770 public void drawIfNeeded() {
771 synchronized (mWindowManagerService.mWindowMap) {
772 if (!mInvalidated) {
773 return;
774 }
775 mInvalidated = false;
776 Canvas canvas = null;
777 try {
778 // Empty dirty rectangle means unspecified.
779 if (mDirtyRect.isEmpty()) {
780 mBounds.getBounds(mDirtyRect);
781 }
782 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
783 canvas = mSurface.lockCanvas(mDirtyRect);
784 if (DEBUG_VIEWPORT_WINDOW) {
785 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
786 }
787 } catch (IllegalArgumentException iae) {
788 /* ignore */
789 } catch (Surface.OutOfResourcesException oore) {
790 /* ignore */
791 }
792 if (canvas == null) {
793 return;
794 }
795 if (DEBUG_VIEWPORT_WINDOW) {
796 Slog.i(LOG_TAG, "Bounds: " + mBounds);
797 }
798 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
799 mPaint.setAlpha(mAlpha);
800 Path path = mBounds.getBoundaryPath();
801 canvas.drawPath(path, mPaint);
802
803 mSurface.unlockCanvasAndPost(canvas);
804
805 if (mAlpha > 0) {
806 mSurfaceControl.show();
807 } else {
808 mSurfaceControl.hide();
809 }
810 }
811 }
812
813 public void releaseSurface() {
814 mSurfaceControl.release();
815 mSurface.release();
816 }
Svet Ganovb21df802014-09-01 19:06:33 -0700817
818 private final class AnimationController extends Handler {
819 private static final String PROPERTY_NAME_ALPHA = "alpha";
820
821 private static final int MIN_ALPHA = 0;
822 private static final int MAX_ALPHA = 255;
823
824 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
825
826 private final ValueAnimator mShowHideFrameAnimator;
827
828 public AnimationController(Context context, Looper looper) {
829 super(looper);
830 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
831 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
832
833 Interpolator interpolator = new DecelerateInterpolator(2.5f);
834 final long longAnimationDuration = context.getResources().getInteger(
835 com.android.internal.R.integer.config_longAnimTime);
836
837 mShowHideFrameAnimator.setInterpolator(interpolator);
838 mShowHideFrameAnimator.setDuration(longAnimationDuration);
839 }
840
841 public void onFrameShownStateChanged(boolean shown, boolean animate) {
842 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
843 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
844 }
845
846 @Override
847 public void handleMessage(Message message) {
848 switch (message.what) {
849 case MSG_FRAME_SHOWN_STATE_CHANGED: {
850 final boolean shown = message.arg1 == 1;
851 final boolean animate = message.arg2 == 1;
852
853 if (animate) {
854 if (mShowHideFrameAnimator.isRunning()) {
855 mShowHideFrameAnimator.reverse();
856 } else {
857 if (shown) {
858 mShowHideFrameAnimator.start();
859 } else {
860 mShowHideFrameAnimator.reverse();
861 }
862 }
863 } else {
864 mShowHideFrameAnimator.cancel();
865 if (shown) {
866 setAlpha(MAX_ALPHA);
867 } else {
868 setAlpha(MIN_ALPHA);
869 }
870 }
871 } break;
872 }
873 }
874 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800875 }
876 }
877
878 private class MyHandler extends Handler {
Phil Weaver70439242016-03-10 15:15:49 -0800879 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -0800880 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
881 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
882 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
883 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
884
885 public MyHandler(Looper looper) {
886 super(looper);
887 }
888
889 @Override
890 public void handleMessage(Message message) {
891 switch (message.what) {
Phil Weaver70439242016-03-10 15:15:49 -0800892 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500893 final SomeArgs args = (SomeArgs) message.obj;
894 final Region magnifiedBounds = (Region) args.arg1;
Phil Weaver70439242016-03-10 15:15:49 -0800895 mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500896 magnifiedBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800897 } break;
898
899 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
900 SomeArgs args = (SomeArgs) message.obj;
901 final int left = args.argi1;
902 final int top = args.argi2;
903 final int right = args.argi3;
904 final int bottom = args.argi4;
905 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
906 args.recycle();
907 } break;
908
909 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
910 mCallbacks.onUserContextChanged();
911 } break;
912
913 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
914 final int rotation = message.arg1;
915 mCallbacks.onRotationChanged(rotation);
916 } break;
917
918 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
919 synchronized (mWindowManagerService.mWindowMap) {
920 if (mMagnifedViewport.isMagnifyingLocked()) {
921 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
922 mWindowManagerService.scheduleAnimationLocked();
923 }
924 }
925 } break;
926 }
927 }
928 }
929 }
930
931 /**
932 * This class encapsulates the functionality related to computing the windows
933 * reported for accessibility purposes. These windows are all windows a sighted
934 * user can see on the screen.
935 */
936 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800937 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
938 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800939
940 private static final boolean DEBUG = false;
941
942 private final SparseArray<WindowState> mTempWindowStates =
943 new SparseArray<WindowState>();
944
945 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
946
947 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
948
949 private final RectF mTempRectF = new RectF();
950
951 private final Matrix mTempMatrix = new Matrix();
952
953 private final Point mTempPoint = new Point();
954
955 private final Rect mTempRect = new Rect();
956
957 private final Region mTempRegion = new Region();
958
959 private final Region mTempRegion1 = new Region();
960
961 private final Context mContext;
962
963 private final WindowManagerService mWindowManagerService;
964
965 private final Handler mHandler;
966
967 private final WindowsForAccessibilityCallback mCallback;
968
Svetoslavf7174e82014-06-12 11:29:35 -0700969 private final long mRecurringAccessibilityEventsIntervalMillis;
970
Svetoslav8e3feb12014-02-24 13:46:47 -0800971 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
972 WindowsForAccessibilityCallback callback) {
973 mContext = windowManagerService.mContext;
974 mWindowManagerService = windowManagerService;
975 mCallback = callback;
976 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700977 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
978 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800979 computeChangedWindows();
980 }
981
Svetoslav3a0d8782014-12-04 12:50:11 -0800982 public void performComputeChangedWindowsNotLocked() {
983 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
984 computeChangedWindows();
985 }
986
Svetoslavf7174e82014-06-12 11:29:35 -0700987 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -0800988 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -0700989 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
990 mRecurringAccessibilityEventsIntervalMillis);
991 }
992 }
993
Svetoslav8e3feb12014-02-24 13:46:47 -0800994 public void computeChangedWindows() {
995 if (DEBUG) {
996 Slog.i(LOG_TAG, "computeChangedWindows()");
997 }
998
Svetoslav3a0d8782014-12-04 12:50:11 -0800999 boolean windowsChanged = false;
1000 List<WindowInfo> windows = new ArrayList<WindowInfo>();
1001
Svetoslav8e3feb12014-02-24 13:46:47 -08001002 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -07001003 // Do not send the windows if there is no current focus as
1004 // the window manager is still looking for where to put it.
1005 // We will do the work when we get a focus change callback.
1006 if (mWindowManagerService.mCurrentFocus == null) {
1007 return;
1008 }
1009
Svetoslav8e3feb12014-02-24 13:46:47 -08001010 WindowManager windowManager = (WindowManager)
1011 mContext.getSystemService(Context.WINDOW_SERVICE);
1012 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1013 final int screenWidth = mTempPoint.x;
1014 final int screenHeight = mTempPoint.y;
1015
1016 Region unaccountedSpace = mTempRegion;
1017 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1018
1019 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1020 populateVisibleWindowsOnScreenLocked(visibleWindows);
1021
Svetoslav8e3feb12014-02-24 13:46:47 -08001022 Set<IBinder> addedWindows = mTempBinderSet;
1023 addedWindows.clear();
1024
Svetoslavf7174e82014-06-12 11:29:35 -07001025 boolean focusedWindowAdded = false;
1026
Svetoslav8e3feb12014-02-24 13:46:47 -08001027 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001028 int skipRemainingWindowsForTaskId = -1;
1029 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001030 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001031 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001032 final int flags = windowState.mAttrs.flags;
Allen Hairf20ac2c2016-02-11 17:42:59 -08001033 final Task task = windowState.getTask();
1034
1035 // If the window is part of a task that we're finished with - ignore.
1036 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1037 continue;
1038 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001039
Svetoslav3a5c7212014-10-14 09:54:26 -07001040 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001041 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001042 continue;
1043 }
1044
Alan Viverette9538eea2014-11-13 14:49:20 -08001045 // Compute the bounds in the screen.
1046 final Rect boundsInScreen = mTempRect;
1047 computeWindowBoundsInScreen(windowState, boundsInScreen);
1048
Svetoslav8e3feb12014-02-24 13:46:47 -08001049 // If the window is completely covered by other windows - ignore.
1050 if (unaccountedSpace.quickReject(boundsInScreen)) {
1051 continue;
1052 }
1053
1054 // Add windows of certain types not covered by modal windows.
1055 if (isReportedWindowType(windowState.mAttrs.type)) {
1056 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001057 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001058 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001059 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001060 if (windowState.isFocused()) {
1061 focusedWindowAdded = true;
1062 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001063 }
1064
Alan Viveretted0c73f42014-11-18 10:25:04 -08001065 // Account for the space this window takes if the window
1066 // is not an accessibility overlay which does not change
1067 // the reported windows.
1068 if (windowState.mAttrs.type !=
1069 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1070 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1071 Region.Op.REVERSE_DIFFERENCE);
1072 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001073
1074 // We figured out what is touchable for the entire screen - done.
1075 if (unaccountedSpace.isEmpty()) {
1076 break;
1077 }
1078
Allen Hairf20ac2c2016-02-11 17:42:59 -08001079 // If a window is modal it prevents other windows from being touched
Svetoslav8e3feb12014-02-24 13:46:47 -08001080 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1081 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Allen Hairf20ac2c2016-02-11 17:42:59 -08001082 if (task != null) {
1083 // If the window is associated with a particular task, we can skip the
1084 // rest of the windows for that task.
1085 skipRemainingWindowsForTasks.add(task.mTaskId);
1086 continue;
1087 } else {
1088 // If the window is not associated with a particular task, then it is
1089 // globally modal. In this case we can skip all remaining windows.
1090 break;
1091 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001092 }
1093 }
1094
Svetoslavf7174e82014-06-12 11:29:35 -07001095 // Always report the focused window.
1096 if (!focusedWindowAdded) {
1097 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1098 WindowState windowState = visibleWindows.valueAt(i);
1099 if (windowState.isFocused()) {
1100 // Compute the bounds in the screen.
1101 Rect boundsInScreen = mTempRect;
1102 computeWindowBoundsInScreen(windowState, boundsInScreen);
1103
1104 // Add the window to the ones to be reported.
1105 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1106 boundsInScreen);
1107 addedWindows.add(window.token);
1108 windows.add(window);
1109 break;
1110 }
1111 }
1112 }
1113
Svetoslav8e3feb12014-02-24 13:46:47 -08001114 // Remove child/parent references to windows that were not added.
1115 final int windowCount = windows.size();
1116 for (int i = 0; i < windowCount; i++) {
1117 WindowInfo window = windows.get(i);
1118 if (!addedWindows.contains(window.parentToken)) {
1119 window.parentToken = null;
1120 }
1121 if (window.childTokens != null) {
1122 final int childTokenCount = window.childTokens.size();
1123 for (int j = childTokenCount - 1; j >= 0; j--) {
1124 if (!addedWindows.contains(window.childTokens.get(j))) {
1125 window.childTokens.remove(j);
1126 }
1127 }
1128 // Leave the child token list if empty.
1129 }
1130 }
1131
1132 visibleWindows.clear();
1133 addedWindows.clear();
1134
1135 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001136 if (mOldWindows.size() != windows.size()) {
1137 // Different size means something changed.
1138 windowsChanged = true;
1139 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1140 // Since we always traverse windows from high to low layer
1141 // the old and new windows at the same index should be the
1142 // same, otherwise something changed.
1143 for (int i = 0; i < windowCount; i++) {
1144 WindowInfo oldWindow = mOldWindows.get(i);
1145 WindowInfo newWindow = windows.get(i);
1146 // We do not care for layer changes given the window
1147 // order does not change. This brings no new information
1148 // to the clients.
1149 if (windowChangedNoLayer(oldWindow, newWindow)) {
1150 windowsChanged = true;
1151 break;
1152 }
1153 }
1154 }
1155
1156 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001157 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001158 }
1159 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001160
1161 // Now we do not hold the lock, so send the windows over.
1162 if (windowsChanged) {
1163 if (DEBUG) {
1164 Log.i(LOG_TAG, "Windows changed:" + windows);
1165 }
1166 mCallback.onWindowsForAccessibilityChanged(windows);
1167 } else {
1168 if (DEBUG) {
1169 Log.i(LOG_TAG, "No windows changed.");
1170 }
1171 }
1172
1173 // Recycle the windows as we do not need them.
1174 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001175 }
1176
Svetoslavf7174e82014-06-12 11:29:35 -07001177 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1178 // Get the touchable frame.
1179 Region touchableRegion = mTempRegion1;
1180 windowState.getTouchableRegion(touchableRegion);
1181 Rect touchableFrame = mTempRect;
1182 touchableRegion.getBounds(touchableFrame);
1183
1184 // Move to origin as all transforms are captured by the matrix.
1185 RectF windowFrame = mTempRectF;
1186 windowFrame.set(touchableFrame);
1187 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1188
1189 // Map the frame to get what appears on the screen.
1190 Matrix matrix = mTempMatrix;
1191 populateTransformationMatrixLocked(windowState, matrix);
1192 matrix.mapRect(windowFrame);
1193
1194 // Got the bounds.
1195 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1196 (int) windowFrame.right, (int) windowFrame.bottom);
1197 }
1198
1199 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1200 Rect boundsInScreen) {
1201 WindowInfo window = WindowInfo.obtain();
1202 window.type = windowState.mAttrs.type;
1203 window.layer = windowState.mLayer;
1204 window.token = windowState.mClient.asBinder();
Phil Weaver9be3c7b2016-04-07 15:15:41 -07001205 window.title = windowState.mAttrs.accessibilityTitle;
1206 if (window.title == null) {
1207 window.title = windowState.mAttrs.getTitle();
1208 }
Phil Weaver396d5492016-03-22 17:53:50 -07001209 window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
Svetoslavf7174e82014-06-12 11:29:35 -07001210
1211 WindowState attachedWindow = windowState.mAttachedWindow;
1212 if (attachedWindow != null) {
1213 window.parentToken = attachedWindow.mClient.asBinder();
1214 }
1215
1216 window.focused = windowState.isFocused();
1217 window.boundsInScreen.set(boundsInScreen);
1218
1219 final int childCount = windowState.mChildWindows.size();
1220 if (childCount > 0) {
1221 if (window.childTokens == null) {
1222 window.childTokens = new ArrayList<IBinder>();
1223 }
1224 for (int j = 0; j < childCount; j++) {
1225 WindowState child = windowState.mChildWindows.get(j);
1226 window.childTokens.add(child.mClient.asBinder());
1227 }
1228 }
1229
1230 return window;
1231 }
1232
Svetoslav8e3feb12014-02-24 13:46:47 -08001233 private void cacheWindows(List<WindowInfo> windows) {
1234 final int oldWindowCount = mOldWindows.size();
1235 for (int i = oldWindowCount - 1; i >= 0; i--) {
1236 mOldWindows.remove(i).recycle();
1237 }
1238 final int newWindowCount = windows.size();
1239 for (int i = 0; i < newWindowCount; i++) {
1240 WindowInfo newWindow = windows.get(i);
1241 mOldWindows.add(WindowInfo.obtain(newWindow));
1242 }
1243 }
1244
1245 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1246 if (oldWindow == newWindow) {
1247 return false;
1248 }
Svetoslavf7174e82014-06-12 11:29:35 -07001249 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001250 return true;
1251 }
Svetoslavf7174e82014-06-12 11:29:35 -07001252 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001253 return true;
1254 }
1255 if (oldWindow.type != newWindow.type) {
1256 return true;
1257 }
1258 if (oldWindow.focused != newWindow.focused) {
1259 return true;
1260 }
1261 if (oldWindow.token == null) {
1262 if (newWindow.token != null) {
1263 return true;
1264 }
1265 } else if (!oldWindow.token.equals(newWindow.token)) {
1266 return true;
1267 }
1268 if (oldWindow.parentToken == null) {
1269 if (newWindow.parentToken != null) {
1270 return true;
1271 }
1272 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1273 return true;
1274 }
1275 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1276 return true;
1277 }
1278 if (oldWindow.childTokens != null && newWindow.childTokens != null
1279 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1280 return true;
1281 }
Phil Weaver396d5492016-03-22 17:53:50 -07001282 if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
1283 return true;
1284 }
1285 if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
1286 return true;
1287 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001288 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}