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