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