Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import android.animation.ObjectAnimator;
     20 import android.animation.ValueAnimator;
     21 import android.app.Service;
     22 import android.content.Context;
     23 import android.graphics.Canvas;
     24 import android.graphics.Color;
     25 import android.graphics.Matrix;
     26 import android.graphics.Paint;
     27 import android.graphics.Path;
     28 import android.graphics.PixelFormat;
     29 import android.graphics.Point;
     30 import android.graphics.PorterDuff.Mode;
     31 import android.graphics.Rect;
     32 import android.graphics.RectF;
     33 import android.graphics.Region;
     34 import android.os.Handler;
     35 import android.os.IBinder;
     36 import android.os.Looper;
     37 import android.os.Message;
     38 import android.util.ArraySet;
     39 import android.util.Log;
     40 import android.util.Slog;
     41 import android.util.SparseArray;
     42 import android.util.TypedValue;
     43 import android.view.MagnificationSpec;
     44 import android.view.Surface;
     45 import android.view.Surface.OutOfResourcesException;
     46 import android.view.SurfaceControl;
     47 import android.view.ViewConfiguration;
     48 import android.view.WindowInfo;
     49 import android.view.WindowManager;
     50 import android.view.WindowManagerInternal.MagnificationCallbacks;
     51 import android.view.WindowManagerInternal.WindowsForAccessibilityCallback;
     52 import android.view.WindowManagerPolicy;
     53 import android.view.animation.DecelerateInterpolator;
     54 import android.view.animation.Interpolator;
     55 
     56 import com.android.internal.R;
     57 import com.android.internal.os.SomeArgs;
     58 
     59 import java.util.ArrayList;
     60 import java.util.List;
     61 import java.util.Set;
     62 
     63 /**
     64  * This class contains the accessibility related logic of the window manger.
     65  */
     66 final class AccessibilityController {
     67 
     68     private final WindowManagerService mWindowManagerService;
     69 
     70     private static final float[] sTempFloats = new float[9];
     71 
     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