AccessibilityController.java revision 3a0d878ab56475276c61d574af7651820a5cea5a
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
17package com.android.server.wm;
18
19import android.animation.ObjectAnimator;
20import android.animation.ValueAnimator;
21import android.app.Service;
22import android.content.Context;
23import android.graphics.Canvas;
24import android.graphics.Color;
25import android.graphics.Matrix;
26import android.graphics.Paint;
27import android.graphics.Path;
28import android.graphics.PixelFormat;
29import android.graphics.Point;
30import android.graphics.PorterDuff.Mode;
31import android.graphics.Rect;
32import android.graphics.RectF;
33import android.graphics.Region;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Looper;
37import android.os.Message;
38import android.util.ArraySet;
39import android.util.Log;
40import android.util.Slog;
41import android.util.SparseArray;
42import android.util.TypedValue;
43import android.view.MagnificationSpec;
44import android.view.Surface;
45import android.view.Surface.OutOfResourcesException;
46import android.view.SurfaceControl;
47import android.view.ViewConfiguration;
48import android.view.WindowInfo;
49import android.view.WindowManager;
50import android.view.WindowManagerInternal.MagnificationCallbacks;
51import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
52import android.view.WindowManagerPolicy;
53import android.view.animation.DecelerateInterpolator;
54import android.view.animation.Interpolator;
55
56import com.android.internal.R;
57import com.android.internal.os.SomeArgs;
58
59import java.util.ArrayList;
60import java.util.List;
61import java.util.Set;
62
63/**
64 * This class contains the accessibility related logic of the window manger.
65 */
66final class AccessibilityController {
67
68    private final WindowManagerService mWindowManagerService;
69
70    private static final float[] sTempFloats = new float[9];
71
72    public AccessibilityController(WindowManagerService service) {
73        mWindowManagerService = service;
74    }
75
76    private DisplayMagnifier mDisplayMagnifier;
77
78    private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
79
80    public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
81        if (callbacks != null) {
82            if (mDisplayMagnifier != null) {
83                throw new IllegalStateException("Magnification callbacks already set!");
84            }
85            mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
86        } else {
87            if  (mDisplayMagnifier == null) {
88                throw new IllegalStateException("Magnification callbacks already cleared!");
89            }
90            mDisplayMagnifier.destroyLocked();
91            mDisplayMagnifier = null;
92        }
93    }
94
95    public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
96        if (callback != null) {
97            if (mWindowsForAccessibilityObserver != null) {
98                throw new IllegalStateException(
99                        "Windows for accessibility callback already set!");
100            }
101            mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
102                    mWindowManagerService, callback);
103        } else {
104            if (mWindowsForAccessibilityObserver == null) {
105                throw new IllegalStateException(
106                        "Windows for accessibility callback already cleared!");
107            }
108            mWindowsForAccessibilityObserver = null;
109        }
110    }
111
112    public void setMagnificationSpecLocked(MagnificationSpec spec) {
113        if (mDisplayMagnifier != null) {
114            mDisplayMagnifier.setMagnificationSpecLocked(spec);
115        }
116        if (mWindowsForAccessibilityObserver != null) {
117            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
118        }
119    }
120
121    public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
122        if (mDisplayMagnifier != null) {
123            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
124        }
125        // Not relevant for the window observer.
126    }
127
128    public void onWindowLayersChangedLocked() {
129        if (mDisplayMagnifier != null) {
130            mDisplayMagnifier.onWindowLayersChangedLocked();
131        }
132        if (mWindowsForAccessibilityObserver != null) {
133            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
134        }
135    }
136
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
146    public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
147        if (mDisplayMagnifier != null) {
148            mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
149        }
150        // Not relevant for the window observer.
151    }
152
153    public void onWindowTransitionLocked(WindowState windowState, int transition) {
154        if (mDisplayMagnifier != null) {
155            mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
156        }
157        if (mWindowsForAccessibilityObserver != null) {
158            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
159        }
160    }
161
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
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. */
184    public void drawMagnifiedRegionBorderIfNeededLocked() {
185        if (mDisplayMagnifier != null) {
186            mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
187        }
188        // Not relevant for the window observer.
189    }
190
191    public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
192        if (mDisplayMagnifier != null) {
193            return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
194        }
195        return null;
196    }
197
198    public boolean hasCallbacksLocked() {
199        return (mDisplayMagnifier != null
200                || mWindowsForAccessibilityObserver != null);
201    }
202
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
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
258        public void setMagnificationSpecLocked(MagnificationSpec spec) {
259            mMagnifedViewport.updateMagnificationSpecLocked(spec);
260            mMagnifedViewport.recomputeBoundsLocked();
261            mWindowManagerService.scheduleAnimationLocked();
262        }
263
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
285        public void onWindowLayersChangedLocked() {
286            if (DEBUG_LAYERS) {
287                Slog.i(LOG_TAG, "Layers changed.");
288            }
289            mMagnifedViewport.recomputeBoundsLocked();
290            mWindowManagerService.scheduleAnimationLocked();
291        }
292
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
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
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
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
389        public void destroyLocked() {
390            mMagnifedViewport.destroyWindow();
391        }
392
393        /** NOTE: This has to be called within a surface transaction. */
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
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
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
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
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
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
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
584            public boolean isMagnifyingLocked() {
585                return mMagnificationSpec.scale > 1.0f;
586            }
587
588            public MagnificationSpec getMagnificationSpecLocked() {
589                return mMagnificationSpec;
590            }
591
592            /** NOTE: This has to be called within a surface transaction. */
593            public void drawWindowIfNeededLocked() {
594                recomputeBoundsLocked();
595                mWindow.drawIfNeeded();
596            }
597
598            public void destroyWindow() {
599                mWindow.releaseSurface();
600            }
601
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
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
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.
683                public int getAlpha() {
684                    synchronized (mWindowManagerService.mWindowMap) {
685                        return mAlpha;
686                    }
687                }
688
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
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
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
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. */
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
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
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
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
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
849            public MyHandler(Looper looper) {
850                super(looper);
851            }
852
853            @Override
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
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
944        public void performComputeChangedWindowsNotLocked() {
945            mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
946            computeChangedWindows();
947        }
948
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
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
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
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
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
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
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
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
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
1263            public MyHandler(Looper looper) {
1264                super(looper, null, false);
1265            }
1266
1267            @Override
1268            @SuppressWarnings("unchecked")
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