blob: bae628ab18929d3d11bfba472c95bec47e71972d [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
Alan Viverette59e53a12016-03-28 13:41:32 -0400127 public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
128 if (mDisplayMagnifier != null) {
129 mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
130 }
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
Alan Viverette59e53a12016-03-28 13:41:32 -0400403 public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
404 mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
405 }
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
427 private final Region mMagnifiedBounds = new Region();
Alan Viverette59e53a12016-03-28 13:41:32 -0400428 private final Region mAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800429 private final Region mOldMagnifiedBounds = new Region();
Alan Viverette214fb682015-11-17 09:47:11 -0500430 private final Region mOldAvailableBounds = new Region();
Svetoslav8e3feb12014-02-24 13:46:47 -0800431
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800432 private final Path mCircularPath;
433
Svetoslav8e3feb12014-02-24 13:46:47 -0800434 private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
435
436 private final WindowManager mWindowManager;
437
Svetoslav7505e332014-08-22 12:14:28 -0700438 private final float mBorderWidth;
Svetoslav8e3feb12014-02-24 13:46:47 -0800439 private final int mHalfBorderWidth;
Svetoslav7505e332014-08-22 12:14:28 -0700440 private final int mDrawBorderInset;
Svetoslav8e3feb12014-02-24 13:46:47 -0800441
442 private final ViewportWindow mWindow;
443
444 private boolean mFullRedrawNeeded;
445
446 public MagnifiedViewport() {
447 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800448 mBorderWidth = mContext.getResources().getDimension(
449 com.android.internal.R.dimen.accessibility_magnification_indicator_width);
Svetoslav7505e332014-08-22 12:14:28 -0700450 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
451 mDrawBorderInset = (int) mBorderWidth / 2;
Svetoslav8e3feb12014-02-24 13:46:47 -0800452 mWindow = new ViewportWindow(mContext);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800453
Adam Powell01f280d2015-05-18 16:07:42 -0700454 if (mContext.getResources().getConfiguration().isScreenRound()) {
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800455 mCircularPath = new Path();
456 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
457 final int centerXY = mTempPoint.x / 2;
458 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
459 } else {
460 mCircularPath = null;
461 }
462
Svetoslav8e3feb12014-02-24 13:46:47 -0800463 recomputeBoundsLocked();
464 }
465
Alan Viverette59e53a12016-03-28 13:41:32 -0400466 public void getBoundsLocked(@NonNull Region outMagnified,
467 @NonNull Region outAvailable) {
468 outMagnified.set(mMagnifiedBounds);
469 outAvailable.set(mAvailableBounds);
470 }
471
Svetoslav8e3feb12014-02-24 13:46:47 -0800472 public void updateMagnificationSpecLocked(MagnificationSpec spec) {
473 if (spec != null) {
474 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
475 } else {
476 mMagnificationSpec.clear();
477 }
478 // If this message is pending we are in a rotation animation and do not want
479 // to show the border. We will do so when the pending message is handled.
Svetoslav7505e332014-08-22 12:14:28 -0700480 if (!mHandler.hasMessages(
481 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800482 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
483 }
484 }
485
486 public void recomputeBoundsLocked() {
487 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
488 final int screenWidth = mTempPoint.x;
489 final int screenHeight = mTempPoint.y;
490
Alan Viverette59e53a12016-03-28 13:41:32 -0400491 mMagnifiedBounds.set(0, 0, 0, 0);
492 mAvailableBounds.set(0, 0, screenWidth, screenHeight);
Svetoslav8e3feb12014-02-24 13:46:47 -0800493
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800494 if (mCircularPath != null) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400495 mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
Casey Burkhardtd29a1e42015-02-12 14:07:55 -0800496 }
497
Svetoslav8e3feb12014-02-24 13:46:47 -0800498 Region nonMagnifiedBounds = mTempRegion4;
Svet Ganovb21df802014-09-01 19:06:33 -0700499 nonMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800500
501 SparseArray<WindowState> visibleWindows = mTempWindowStates;
502 visibleWindows.clear();
503 populateWindowsOnScreenLocked(visibleWindows);
504
505 final int visibleWindowCount = visibleWindows.size();
506 for (int i = visibleWindowCount - 1; i >= 0; i--) {
507 WindowState windowState = visibleWindows.valueAt(i);
508 if (windowState.mAttrs.type == WindowManager
509 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
510 continue;
511 }
512
Phil Weaver65c06702016-03-15 15:33:46 -0700513 // Consider the touchable portion of the window
Svetoslav8e3feb12014-02-24 13:46:47 -0800514 Matrix matrix = mTempMatrix;
515 populateTransformationMatrixLocked(windowState, matrix);
Phil Weaver65c06702016-03-15 15:33:46 -0700516 Region touchableRegion = mTempRegion3;
517 windowState.getTouchableRegion(touchableRegion);
518 Rect touchableFrame = mTempRect1;
519 touchableRegion.getBounds(touchableFrame);
Svetoslav8e3feb12014-02-24 13:46:47 -0800520 RectF windowFrame = mTempRectF;
Phil Weaver65c06702016-03-15 15:33:46 -0700521 windowFrame.set(touchableFrame);
522 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
523 matrix.mapRect(windowFrame);
524 Region windowBounds = mTempRegion2;
525 windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
526 (int) windowFrame.right, (int) windowFrame.bottom);
527 // Only update new regions
528 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
529 portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
530 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
531 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800532
533 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400534 mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
535 mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
Svetoslav8e3feb12014-02-24 13:46:47 -0800536 } else {
Svetoslav8e3feb12014-02-24 13:46:47 -0800537 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
Alan Viverette59e53a12016-03-28 13:41:32 -0400538 mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
Svetoslav8e3feb12014-02-24 13:46:47 -0800539 }
540
Phil Weaver65c06702016-03-15 15:33:46 -0700541 // Update accounted bounds
Svetoslav8e3feb12014-02-24 13:46:47 -0800542 Region accountedBounds = mTempRegion2;
Alan Viverette59e53a12016-03-28 13:41:32 -0400543 accountedBounds.set(mMagnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800544 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
545 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
546
547 if (accountedBounds.isRect()) {
548 Rect accountedFrame = mTempRect1;
549 accountedBounds.getBounds(accountedFrame);
550 if (accountedFrame.width() == screenWidth
551 && accountedFrame.height() == screenHeight) {
552 break;
553 }
554 }
555 }
556
557 visibleWindows.clear();
558
Alan Viverette59e53a12016-03-28 13:41:32 -0400559 mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
Svetoslav7505e332014-08-22 12:14:28 -0700560 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Svetoslav8e3feb12014-02-24 13:46:47 -0800561 Region.Op.INTERSECT);
562
Alan Viverette59e53a12016-03-28 13:41:32 -0400563 final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
564 final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500565 if (magnifiedChanged || availableChanged) {
566 if (magnifiedChanged) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400567 mWindow.setBounds(mMagnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500568 Rect dirtyRect = mTempRect1;
569 if (mFullRedrawNeeded) {
570 mFullRedrawNeeded = false;
571 dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
572 screenWidth - mDrawBorderInset,
573 screenHeight - mDrawBorderInset);
574 mWindow.invalidate(dirtyRect);
575 } else {
576 Region dirtyRegion = mTempRegion3;
Alan Viverette59e53a12016-03-28 13:41:32 -0400577 dirtyRegion.set(mMagnifiedBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500578 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
579 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
580 dirtyRegion.getBounds(dirtyRect);
581 mWindow.invalidate(dirtyRect);
582 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800583
Alan Viverette59e53a12016-03-28 13:41:32 -0400584 mOldMagnifiedBounds.set(mMagnifiedBounds);
Svetoslav8e3feb12014-02-24 13:46:47 -0800585 }
586
Alan Viverette214fb682015-11-17 09:47:11 -0500587 if (availableChanged) {
Alan Viverette59e53a12016-03-28 13:41:32 -0400588 mOldAvailableBounds.set(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500589 }
590
591 final SomeArgs args = SomeArgs.obtain();
Alan Viverette59e53a12016-03-28 13:41:32 -0400592 args.arg1 = Region.obtain(mMagnifiedBounds);
593 args.arg2 = Region.obtain(mAvailableBounds);
Alan Viverette214fb682015-11-17 09:47:11 -0500594 mHandler.obtainMessage(
595 MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
Svetoslav8e3feb12014-02-24 13:46:47 -0800596 }
597 }
598
599 public void onRotationChangedLocked() {
600 // If we are magnifying, hide the magnified border window immediately so
601 // the user does not see strange artifacts during rotation. The screenshot
602 // used for rotation has already the border. After the rotation is complete
603 // we will show the border.
604 if (isMagnifyingLocked()) {
605 setMagnifiedRegionBorderShownLocked(false, false);
606 final long delay = (long) (mLongAnimationDuration
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700607 * mWindowManagerService.getWindowAnimationScaleLocked());
Svetoslav8e3feb12014-02-24 13:46:47 -0800608 Message message = mHandler.obtainMessage(
609 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
610 mHandler.sendMessageDelayed(message, delay);
611 }
612 recomputeBoundsLocked();
613 mWindow.updateSize();
614 }
615
616 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
617 if (shown) {
618 mFullRedrawNeeded = true;
Svet Ganovb21df802014-09-01 19:06:33 -0700619 mOldMagnifiedBounds.set(0, 0, 0, 0);
Svetoslav8e3feb12014-02-24 13:46:47 -0800620 }
621 mWindow.setShown(shown, animate);
622 }
623
624 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
625 MagnificationSpec spec = mMagnificationSpec;
626 mMagnifiedBounds.getBounds(rect);
627 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
628 rect.scale(1.0f / spec.scale);
629 }
630
631 public boolean isMagnifyingLocked() {
632 return mMagnificationSpec.scale > 1.0f;
633 }
634
635 public MagnificationSpec getMagnificationSpecLocked() {
636 return mMagnificationSpec;
637 }
638
639 /** NOTE: This has to be called within a surface transaction. */
640 public void drawWindowIfNeededLocked() {
641 recomputeBoundsLocked();
642 mWindow.drawIfNeeded();
643 }
644
645 public void destroyWindow() {
646 mWindow.releaseSurface();
647 }
648
649 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
650 DisplayContent displayContent = mWindowManagerService
651 .getDefaultDisplayContentLocked();
652 WindowList windowList = displayContent.getWindowList();
653 final int windowCount = windowList.size();
654 for (int i = 0; i < windowCount; i++) {
655 WindowState windowState = windowList.get(i);
Craig Mautner165be0c2015-01-27 15:16:58 -0800656 if (windowState.isOnScreen() &&
657 !windowState.mWinAnimator.mEnterAnimationPending) {
Svetoslav8e3feb12014-02-24 13:46:47 -0800658 outWindows.put(windowState.mLayer, windowState);
659 }
660 }
661 }
662
663 private final class ViewportWindow {
664 private static final String SURFACE_TITLE = "Magnification Overlay";
665
Svetoslav8e3feb12014-02-24 13:46:47 -0800666 private final Region mBounds = new Region();
667 private final Rect mDirtyRect = new Rect();
668 private final Paint mPaint = new Paint();
669
Svetoslav8e3feb12014-02-24 13:46:47 -0800670 private final SurfaceControl mSurfaceControl;
671 private final Surface mSurface = new Surface();
672
Svet Ganovb21df802014-09-01 19:06:33 -0700673 private final AnimationController mAnimationController;
674
Svetoslav8e3feb12014-02-24 13:46:47 -0800675 private boolean mShown;
676 private int mAlpha;
677
678 private boolean mInvalidated;
679
680 public ViewportWindow(Context context) {
681 SurfaceControl surfaceControl = null;
682 try {
683 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
684 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
685 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
686 SurfaceControl.HIDDEN);
687 } catch (OutOfResourcesException oore) {
688 /* ignore */
689 }
690 mSurfaceControl = surfaceControl;
691 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
692 .getLayerStack());
693 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
694 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
695 * WindowManagerService.TYPE_LAYER_MULTIPLIER);
696 mSurfaceControl.setPosition(0, 0);
697 mSurface.copyFrom(mSurfaceControl);
698
Svet Ganovb21df802014-09-01 19:06:33 -0700699 mAnimationController = new AnimationController(context,
700 mWindowManagerService.mH.getLooper());
701
Svetoslav8e3feb12014-02-24 13:46:47 -0800702 TypedValue typedValue = new TypedValue();
703 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
704 typedValue, true);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700705 final int borderColor = context.getColor(typedValue.resourceId);
Svetoslav8e3feb12014-02-24 13:46:47 -0800706
707 mPaint.setStyle(Paint.Style.STROKE);
708 mPaint.setStrokeWidth(mBorderWidth);
709 mPaint.setColor(borderColor);
710
Svetoslav8e3feb12014-02-24 13:46:47 -0800711 mInvalidated = true;
712 }
713
714 public void setShown(boolean shown, boolean animate) {
715 synchronized (mWindowManagerService.mWindowMap) {
716 if (mShown == shown) {
717 return;
718 }
719 mShown = shown;
Svet Ganovb21df802014-09-01 19:06:33 -0700720 mAnimationController.onFrameShownStateChanged(shown, animate);
Svetoslav8e3feb12014-02-24 13:46:47 -0800721 if (DEBUG_VIEWPORT_WINDOW) {
722 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
723 }
724 }
725 }
726
727 @SuppressWarnings("unused")
728 // Called reflectively from an animator.
729 public int getAlpha() {
730 synchronized (mWindowManagerService.mWindowMap) {
731 return mAlpha;
732 }
733 }
734
735 public void setAlpha(int alpha) {
736 synchronized (mWindowManagerService.mWindowMap) {
737 if (mAlpha == alpha) {
738 return;
739 }
740 mAlpha = alpha;
741 invalidate(null);
742 if (DEBUG_VIEWPORT_WINDOW) {
743 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
744 }
745 }
746 }
747
748 public void setBounds(Region bounds) {
749 synchronized (mWindowManagerService.mWindowMap) {
750 if (mBounds.equals(bounds)) {
751 return;
752 }
753 mBounds.set(bounds);
754 invalidate(mDirtyRect);
755 if (DEBUG_VIEWPORT_WINDOW) {
756 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
757 }
758 }
759 }
760
761 public void updateSize() {
762 synchronized (mWindowManagerService.mWindowMap) {
763 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
764 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
765 invalidate(mDirtyRect);
766 }
767 }
768
769 public void invalidate(Rect dirtyRect) {
770 if (dirtyRect != null) {
771 mDirtyRect.set(dirtyRect);
772 } else {
773 mDirtyRect.setEmpty();
774 }
775 mInvalidated = true;
776 mWindowManagerService.scheduleAnimationLocked();
777 }
778
779 /** NOTE: This has to be called within a surface transaction. */
780 public void drawIfNeeded() {
781 synchronized (mWindowManagerService.mWindowMap) {
782 if (!mInvalidated) {
783 return;
784 }
785 mInvalidated = false;
786 Canvas canvas = null;
787 try {
788 // Empty dirty rectangle means unspecified.
789 if (mDirtyRect.isEmpty()) {
790 mBounds.getBounds(mDirtyRect);
791 }
792 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth);
793 canvas = mSurface.lockCanvas(mDirtyRect);
794 if (DEBUG_VIEWPORT_WINDOW) {
795 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect);
796 }
797 } catch (IllegalArgumentException iae) {
798 /* ignore */
799 } catch (Surface.OutOfResourcesException oore) {
800 /* ignore */
801 }
802 if (canvas == null) {
803 return;
804 }
805 if (DEBUG_VIEWPORT_WINDOW) {
806 Slog.i(LOG_TAG, "Bounds: " + mBounds);
807 }
808 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
809 mPaint.setAlpha(mAlpha);
810 Path path = mBounds.getBoundaryPath();
811 canvas.drawPath(path, mPaint);
812
813 mSurface.unlockCanvasAndPost(canvas);
814
815 if (mAlpha > 0) {
816 mSurfaceControl.show();
817 } else {
818 mSurfaceControl.hide();
819 }
820 }
821 }
822
823 public void releaseSurface() {
824 mSurfaceControl.release();
825 mSurface.release();
826 }
Svet Ganovb21df802014-09-01 19:06:33 -0700827
828 private final class AnimationController extends Handler {
829 private static final String PROPERTY_NAME_ALPHA = "alpha";
830
831 private static final int MIN_ALPHA = 0;
832 private static final int MAX_ALPHA = 255;
833
834 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
835
836 private final ValueAnimator mShowHideFrameAnimator;
837
838 public AnimationController(Context context, Looper looper) {
839 super(looper);
840 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
841 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
842
843 Interpolator interpolator = new DecelerateInterpolator(2.5f);
844 final long longAnimationDuration = context.getResources().getInteger(
845 com.android.internal.R.integer.config_longAnimTime);
846
847 mShowHideFrameAnimator.setInterpolator(interpolator);
848 mShowHideFrameAnimator.setDuration(longAnimationDuration);
849 }
850
851 public void onFrameShownStateChanged(boolean shown, boolean animate) {
852 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
853 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
854 }
855
856 @Override
857 public void handleMessage(Message message) {
858 switch (message.what) {
859 case MSG_FRAME_SHOWN_STATE_CHANGED: {
860 final boolean shown = message.arg1 == 1;
861 final boolean animate = message.arg2 == 1;
862
863 if (animate) {
864 if (mShowHideFrameAnimator.isRunning()) {
865 mShowHideFrameAnimator.reverse();
866 } else {
867 if (shown) {
868 mShowHideFrameAnimator.start();
869 } else {
870 mShowHideFrameAnimator.reverse();
871 }
872 }
873 } else {
874 mShowHideFrameAnimator.cancel();
875 if (shown) {
876 setAlpha(MAX_ALPHA);
877 } else {
878 setAlpha(MIN_ALPHA);
879 }
880 }
881 } break;
882 }
883 }
884 }
Svetoslav8e3feb12014-02-24 13:46:47 -0800885 }
886 }
887
888 private class MyHandler extends Handler {
889 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
890 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
891 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
892 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
893 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
894
895 public MyHandler(Looper looper) {
896 super(looper);
897 }
898
899 @Override
900 public void handleMessage(Message message) {
901 switch (message.what) {
902 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
Alan Viverette214fb682015-11-17 09:47:11 -0500903 final SomeArgs args = (SomeArgs) message.obj;
904 final Region magnifiedBounds = (Region) args.arg1;
905 final Region availableBounds = (Region) args.arg2;
906 mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
907 magnifiedBounds.recycle();
908 availableBounds.recycle();
Svetoslav8e3feb12014-02-24 13:46:47 -0800909 } break;
910
911 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
912 SomeArgs args = (SomeArgs) message.obj;
913 final int left = args.argi1;
914 final int top = args.argi2;
915 final int right = args.argi3;
916 final int bottom = args.argi4;
917 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
918 args.recycle();
919 } break;
920
921 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
922 mCallbacks.onUserContextChanged();
923 } break;
924
925 case MESSAGE_NOTIFY_ROTATION_CHANGED: {
926 final int rotation = message.arg1;
927 mCallbacks.onRotationChanged(rotation);
928 } break;
929
930 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
931 synchronized (mWindowManagerService.mWindowMap) {
932 if (mMagnifedViewport.isMagnifyingLocked()) {
933 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
934 mWindowManagerService.scheduleAnimationLocked();
935 }
936 }
937 } break;
938 }
939 }
940 }
941 }
942
943 /**
944 * This class encapsulates the functionality related to computing the windows
945 * reported for accessibility purposes. These windows are all windows a sighted
946 * user can see on the screen.
947 */
948 private static final class WindowsForAccessibilityObserver {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800949 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
950 "WindowsForAccessibilityObserver" : TAG_WM;
Svetoslav8e3feb12014-02-24 13:46:47 -0800951
952 private static final boolean DEBUG = false;
953
954 private final SparseArray<WindowState> mTempWindowStates =
955 new SparseArray<WindowState>();
956
957 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
958
959 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
960
961 private final RectF mTempRectF = new RectF();
962
963 private final Matrix mTempMatrix = new Matrix();
964
965 private final Point mTempPoint = new Point();
966
967 private final Rect mTempRect = new Rect();
968
969 private final Region mTempRegion = new Region();
970
971 private final Region mTempRegion1 = new Region();
972
973 private final Context mContext;
974
975 private final WindowManagerService mWindowManagerService;
976
977 private final Handler mHandler;
978
979 private final WindowsForAccessibilityCallback mCallback;
980
Svetoslavf7174e82014-06-12 11:29:35 -0700981 private final long mRecurringAccessibilityEventsIntervalMillis;
982
Svetoslav8e3feb12014-02-24 13:46:47 -0800983 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
984 WindowsForAccessibilityCallback callback) {
985 mContext = windowManagerService.mContext;
986 mWindowManagerService = windowManagerService;
987 mCallback = callback;
988 mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
Svetoslavf7174e82014-06-12 11:29:35 -0700989 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
990 .getSendRecurringAccessibilityEventsInterval();
Svetoslav8e3feb12014-02-24 13:46:47 -0800991 computeChangedWindows();
992 }
993
Svetoslav3a0d8782014-12-04 12:50:11 -0800994 public void performComputeChangedWindowsNotLocked() {
995 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
996 computeChangedWindows();
997 }
998
Svetoslavf7174e82014-06-12 11:29:35 -0700999 public void scheduleComputeChangedWindowsLocked() {
Svetoslav3a0d8782014-12-04 12:50:11 -08001000 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
Svetoslavf7174e82014-06-12 11:29:35 -07001001 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1002 mRecurringAccessibilityEventsIntervalMillis);
1003 }
1004 }
1005
Svetoslav8e3feb12014-02-24 13:46:47 -08001006 public void computeChangedWindows() {
1007 if (DEBUG) {
1008 Slog.i(LOG_TAG, "computeChangedWindows()");
1009 }
1010
Svetoslav3a0d8782014-12-04 12:50:11 -08001011 boolean windowsChanged = false;
1012 List<WindowInfo> windows = new ArrayList<WindowInfo>();
1013
Svetoslav8e3feb12014-02-24 13:46:47 -08001014 synchronized (mWindowManagerService.mWindowMap) {
Svetoslavf7174e82014-06-12 11:29:35 -07001015 // Do not send the windows if there is no current focus as
1016 // the window manager is still looking for where to put it.
1017 // We will do the work when we get a focus change callback.
1018 if (mWindowManagerService.mCurrentFocus == null) {
1019 return;
1020 }
1021
Svetoslav8e3feb12014-02-24 13:46:47 -08001022 WindowManager windowManager = (WindowManager)
1023 mContext.getSystemService(Context.WINDOW_SERVICE);
1024 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
1025 final int screenWidth = mTempPoint.x;
1026 final int screenHeight = mTempPoint.y;
1027
1028 Region unaccountedSpace = mTempRegion;
1029 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1030
1031 SparseArray<WindowState> visibleWindows = mTempWindowStates;
1032 populateVisibleWindowsOnScreenLocked(visibleWindows);
1033
Svetoslav8e3feb12014-02-24 13:46:47 -08001034 Set<IBinder> addedWindows = mTempBinderSet;
1035 addedWindows.clear();
1036
Svetoslavf7174e82014-06-12 11:29:35 -07001037 boolean focusedWindowAdded = false;
1038
Svetoslav8e3feb12014-02-24 13:46:47 -08001039 final int visibleWindowCount = visibleWindows.size();
Allen Hairf20ac2c2016-02-11 17:42:59 -08001040 int skipRemainingWindowsForTaskId = -1;
1041 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
Svetoslav8e3feb12014-02-24 13:46:47 -08001042 for (int i = visibleWindowCount - 1; i >= 0; i--) {
Alan Viverette9538eea2014-11-13 14:49:20 -08001043 final WindowState windowState = visibleWindows.valueAt(i);
Svetoslav8e3feb12014-02-24 13:46:47 -08001044 final int flags = windowState.mAttrs.flags;
Allen Hairf20ac2c2016-02-11 17:42:59 -08001045 final Task task = windowState.getTask();
1046
1047 // If the window is part of a task that we're finished with - ignore.
1048 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
1049 continue;
1050 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001051
Svetoslav3a5c7212014-10-14 09:54:26 -07001052 // If the window is not touchable - ignore.
Svetoslavf7174e82014-06-12 11:29:35 -07001053 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001054 continue;
1055 }
1056
Alan Viverette9538eea2014-11-13 14:49:20 -08001057 // Compute the bounds in the screen.
1058 final Rect boundsInScreen = mTempRect;
1059 computeWindowBoundsInScreen(windowState, boundsInScreen);
1060
Svetoslav8e3feb12014-02-24 13:46:47 -08001061 // If the window is completely covered by other windows - ignore.
1062 if (unaccountedSpace.quickReject(boundsInScreen)) {
1063 continue;
1064 }
1065
1066 // Add windows of certain types not covered by modal windows.
1067 if (isReportedWindowType(windowState.mAttrs.type)) {
1068 // Add the window to the ones to be reported.
Svetoslavf7174e82014-06-12 11:29:35 -07001069 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
Svetoslav8e3feb12014-02-24 13:46:47 -08001070 addedWindows.add(window.token);
Svetoslav8e3feb12014-02-24 13:46:47 -08001071 windows.add(window);
Svetoslavf7174e82014-06-12 11:29:35 -07001072 if (windowState.isFocused()) {
1073 focusedWindowAdded = true;
1074 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001075 }
1076
Alan Viveretted0c73f42014-11-18 10:25:04 -08001077 // Account for the space this window takes if the window
1078 // is not an accessibility overlay which does not change
1079 // the reported windows.
1080 if (windowState.mAttrs.type !=
1081 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1082 unaccountedSpace.op(boundsInScreen, unaccountedSpace,
1083 Region.Op.REVERSE_DIFFERENCE);
1084 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001085
1086 // We figured out what is touchable for the entire screen - done.
1087 if (unaccountedSpace.isEmpty()) {
1088 break;
1089 }
1090
Allen Hairf20ac2c2016-02-11 17:42:59 -08001091 // If a window is modal it prevents other windows from being touched
Svetoslav8e3feb12014-02-24 13:46:47 -08001092 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1093 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
Allen Hairf20ac2c2016-02-11 17:42:59 -08001094 if (task != null) {
1095 // If the window is associated with a particular task, we can skip the
1096 // rest of the windows for that task.
1097 skipRemainingWindowsForTasks.add(task.mTaskId);
1098 continue;
1099 } else {
1100 // If the window is not associated with a particular task, then it is
1101 // globally modal. In this case we can skip all remaining windows.
1102 break;
1103 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001104 }
1105 }
1106
Svetoslavf7174e82014-06-12 11:29:35 -07001107 // Always report the focused window.
1108 if (!focusedWindowAdded) {
1109 for (int i = visibleWindowCount - 1; i >= 0; i--) {
1110 WindowState windowState = visibleWindows.valueAt(i);
1111 if (windowState.isFocused()) {
1112 // Compute the bounds in the screen.
1113 Rect boundsInScreen = mTempRect;
1114 computeWindowBoundsInScreen(windowState, boundsInScreen);
1115
1116 // Add the window to the ones to be reported.
1117 WindowInfo window = obtainPopulatedWindowInfo(windowState,
1118 boundsInScreen);
1119 addedWindows.add(window.token);
1120 windows.add(window);
1121 break;
1122 }
1123 }
1124 }
1125
Svetoslav8e3feb12014-02-24 13:46:47 -08001126 // Remove child/parent references to windows that were not added.
1127 final int windowCount = windows.size();
1128 for (int i = 0; i < windowCount; i++) {
1129 WindowInfo window = windows.get(i);
1130 if (!addedWindows.contains(window.parentToken)) {
1131 window.parentToken = null;
1132 }
1133 if (window.childTokens != null) {
1134 final int childTokenCount = window.childTokens.size();
1135 for (int j = childTokenCount - 1; j >= 0; j--) {
1136 if (!addedWindows.contains(window.childTokens.get(j))) {
1137 window.childTokens.remove(j);
1138 }
1139 }
1140 // Leave the child token list if empty.
1141 }
1142 }
1143
1144 visibleWindows.clear();
1145 addedWindows.clear();
1146
1147 // We computed the windows and if they changed notify the client.
Svetoslav8e3feb12014-02-24 13:46:47 -08001148 if (mOldWindows.size() != windows.size()) {
1149 // Different size means something changed.
1150 windowsChanged = true;
1151 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
1152 // Since we always traverse windows from high to low layer
1153 // the old and new windows at the same index should be the
1154 // same, otherwise something changed.
1155 for (int i = 0; i < windowCount; i++) {
1156 WindowInfo oldWindow = mOldWindows.get(i);
1157 WindowInfo newWindow = windows.get(i);
1158 // We do not care for layer changes given the window
1159 // order does not change. This brings no new information
1160 // to the clients.
1161 if (windowChangedNoLayer(oldWindow, newWindow)) {
1162 windowsChanged = true;
1163 break;
1164 }
1165 }
1166 }
1167
1168 if (windowsChanged) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001169 cacheWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001170 }
1171 }
Svetoslav3a0d8782014-12-04 12:50:11 -08001172
1173 // Now we do not hold the lock, so send the windows over.
1174 if (windowsChanged) {
1175 if (DEBUG) {
1176 Log.i(LOG_TAG, "Windows changed:" + windows);
1177 }
1178 mCallback.onWindowsForAccessibilityChanged(windows);
1179 } else {
1180 if (DEBUG) {
1181 Log.i(LOG_TAG, "No windows changed.");
1182 }
1183 }
1184
1185 // Recycle the windows as we do not need them.
1186 clearAndRecycleWindows(windows);
Svetoslav8e3feb12014-02-24 13:46:47 -08001187 }
1188
Svetoslavf7174e82014-06-12 11:29:35 -07001189 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
1190 // Get the touchable frame.
1191 Region touchableRegion = mTempRegion1;
1192 windowState.getTouchableRegion(touchableRegion);
1193 Rect touchableFrame = mTempRect;
1194 touchableRegion.getBounds(touchableFrame);
1195
1196 // Move to origin as all transforms are captured by the matrix.
1197 RectF windowFrame = mTempRectF;
1198 windowFrame.set(touchableFrame);
1199 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
1200
1201 // Map the frame to get what appears on the screen.
1202 Matrix matrix = mTempMatrix;
1203 populateTransformationMatrixLocked(windowState, matrix);
1204 matrix.mapRect(windowFrame);
1205
1206 // Got the bounds.
1207 outBounds.set((int) windowFrame.left, (int) windowFrame.top,
1208 (int) windowFrame.right, (int) windowFrame.bottom);
1209 }
1210
1211 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
1212 Rect boundsInScreen) {
1213 WindowInfo window = WindowInfo.obtain();
1214 window.type = windowState.mAttrs.type;
1215 window.layer = windowState.mLayer;
1216 window.token = windowState.mClient.asBinder();
Phil Weaver396d5492016-03-22 17:53:50 -07001217 window.title = windowState.mAttrs.getTitle();
1218 window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
Svetoslavf7174e82014-06-12 11:29:35 -07001219
1220 WindowState attachedWindow = windowState.mAttachedWindow;
1221 if (attachedWindow != null) {
1222 window.parentToken = attachedWindow.mClient.asBinder();
1223 }
1224
1225 window.focused = windowState.isFocused();
1226 window.boundsInScreen.set(boundsInScreen);
1227
1228 final int childCount = windowState.mChildWindows.size();
1229 if (childCount > 0) {
1230 if (window.childTokens == null) {
1231 window.childTokens = new ArrayList<IBinder>();
1232 }
1233 for (int j = 0; j < childCount; j++) {
1234 WindowState child = windowState.mChildWindows.get(j);
1235 window.childTokens.add(child.mClient.asBinder());
1236 }
1237 }
1238
1239 return window;
1240 }
1241
Svetoslav8e3feb12014-02-24 13:46:47 -08001242 private void cacheWindows(List<WindowInfo> windows) {
1243 final int oldWindowCount = mOldWindows.size();
1244 for (int i = oldWindowCount - 1; i >= 0; i--) {
1245 mOldWindows.remove(i).recycle();
1246 }
1247 final int newWindowCount = windows.size();
1248 for (int i = 0; i < newWindowCount; i++) {
1249 WindowInfo newWindow = windows.get(i);
1250 mOldWindows.add(WindowInfo.obtain(newWindow));
1251 }
1252 }
1253
1254 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
1255 if (oldWindow == newWindow) {
1256 return false;
1257 }
Svetoslavf7174e82014-06-12 11:29:35 -07001258 if (oldWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001259 return true;
1260 }
Svetoslavf7174e82014-06-12 11:29:35 -07001261 if (newWindow == null) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001262 return true;
1263 }
1264 if (oldWindow.type != newWindow.type) {
1265 return true;
1266 }
1267 if (oldWindow.focused != newWindow.focused) {
1268 return true;
1269 }
1270 if (oldWindow.token == null) {
1271 if (newWindow.token != null) {
1272 return true;
1273 }
1274 } else if (!oldWindow.token.equals(newWindow.token)) {
1275 return true;
1276 }
1277 if (oldWindow.parentToken == null) {
1278 if (newWindow.parentToken != null) {
1279 return true;
1280 }
1281 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
1282 return true;
1283 }
1284 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
1285 return true;
1286 }
1287 if (oldWindow.childTokens != null && newWindow.childTokens != null
1288 && !oldWindow.childTokens.equals(newWindow.childTokens)) {
1289 return true;
1290 }
Phil Weaver396d5492016-03-22 17:53:50 -07001291 if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
1292 return true;
1293 }
1294 if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
1295 return true;
1296 }
Svetoslav8e3feb12014-02-24 13:46:47 -08001297 return false;
1298 }
1299
Svetoslav3a0d8782014-12-04 12:50:11 -08001300 private static void clearAndRecycleWindows(List<WindowInfo> windows) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001301 final int windowCount = windows.size();
1302 for (int i = windowCount - 1; i >= 0; i--) {
1303 windows.remove(i).recycle();
1304 }
1305 }
1306
1307 private static boolean isReportedWindowType(int windowType) {
1308 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
1309 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1310 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1311 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1312 && windowType != WindowManager.LayoutParams.TYPE_DRAG
Selim Cinekf83e8242015-05-19 18:08:14 -07001313 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
Svetoslav8e3feb12014-02-24 13:46:47 -08001314 && windowType != WindowManager.LayoutParams.TYPE_POINTER
Svetoslav8e3feb12014-02-24 13:46:47 -08001315 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
1316 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1317 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1318 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1319 }
1320
1321 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
1322 DisplayContent displayContent = mWindowManagerService
1323 .getDefaultDisplayContentLocked();
1324 WindowList windowList = displayContent.getWindowList();
1325 final int windowCount = windowList.size();
1326 for (int i = 0; i < windowCount; i++) {
1327 WindowState windowState = windowList.get(i);
1328 if (windowState.isVisibleLw()) {
1329 outWindows.put(windowState.mLayer, windowState);
1330 }
1331 }
1332 }
1333
1334 private class MyHandler extends Handler {
Svetoslavf7174e82014-06-12 11:29:35 -07001335 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
Svetoslav8e3feb12014-02-24 13:46:47 -08001336
1337 public MyHandler(Looper looper) {
1338 super(looper, null, false);
1339 }
1340
1341 @Override
1342 @SuppressWarnings("unchecked")
1343 public void handleMessage(Message message) {
1344 switch (message.what) {
Svetoslavf7174e82014-06-12 11:29:35 -07001345 case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1346 computeChangedWindows();
1347 } break;
Svetoslav8e3feb12014-02-24 13:46:47 -08001348 }
1349 }
1350 }
1351 }
1352}