AccessibilityController.java revision 6170cca05eb13cfb44c8d13e7a447cd24f27a62c
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 int mBorderWidth; 416 private final int mHalfBorderWidth; 417 418 private final ViewportWindow mWindow; 419 420 private boolean mFullRedrawNeeded; 421 422 public MagnifiedViewport() { 423 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE); 424 mBorderWidth = (int) TypedValue.applyDimension( 425 TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP, 426 mContext.getResources().getDisplayMetrics()); 427 mHalfBorderWidth = (int) (mBorderWidth + 0.5) / 2; 428 mWindow = new ViewportWindow(mContext); 429 recomputeBoundsLocked(); 430 } 431 432 public void updateMagnificationSpecLocked(MagnificationSpec spec) { 433 if (spec != null) { 434 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY); 435 } else { 436 mMagnificationSpec.clear(); 437 } 438 // If this message is pending we are in a rotation animation and do not want 439 // to show the border. We will do so when the pending message is handled. 440 if (!mHandler.hasMessages(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) { 441 setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true); 442 } 443 } 444 445 public void recomputeBoundsLocked() { 446 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); 447 final int screenWidth = mTempPoint.x; 448 final int screenHeight = mTempPoint.y; 449 450 Region magnifiedBounds = mMagnifiedBounds; 451 magnifiedBounds.set(0, 0, 0, 0); 452 453 Region availableBounds = mTempRegion1; 454 availableBounds.set(0, 0, screenWidth, screenHeight); 455 456 Region nonMagnifiedBounds = mTempRegion4; 457 nonMagnifiedBounds.set(0, 0, 0, 0); 458 459 SparseArray<WindowState> visibleWindows = mTempWindowStates; 460 visibleWindows.clear(); 461 populateWindowsOnScreenLocked(visibleWindows); 462 463 final int visibleWindowCount = visibleWindows.size(); 464 for (int i = visibleWindowCount - 1; i >= 0; i--) { 465 WindowState windowState = visibleWindows.valueAt(i); 466 if (windowState.mAttrs.type == WindowManager 467 .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) { 468 continue; 469 } 470 471 Region windowBounds = mTempRegion2; 472 Matrix matrix = mTempMatrix; 473 populateTransformationMatrixLocked(windowState, matrix); 474 RectF windowFrame = mTempRectF; 475 476 if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) { 477 windowFrame.set(windowState.mFrame); 478 windowFrame.offset(-windowFrame.left, -windowFrame.top); 479 matrix.mapRect(windowFrame); 480 windowBounds.set((int) windowFrame.left, (int) windowFrame.top, 481 (int) windowFrame.right, (int) windowFrame.bottom); 482 magnifiedBounds.op(windowBounds, Region.Op.UNION); 483 magnifiedBounds.op(availableBounds, Region.Op.INTERSECT); 484 } else { 485 Region touchableRegion = mTempRegion3; 486 windowState.getTouchableRegion(touchableRegion); 487 Rect touchableFrame = mTempRect1; 488 touchableRegion.getBounds(touchableFrame); 489 windowFrame.set(touchableFrame); 490 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top); 491 matrix.mapRect(windowFrame); 492 windowBounds.set((int) windowFrame.left, (int) windowFrame.top, 493 (int) windowFrame.right, (int) windowFrame.bottom); 494 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION); 495 windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE); 496 availableBounds.op(windowBounds, Region.Op.DIFFERENCE); 497 } 498 499 Region accountedBounds = mTempRegion2; 500 accountedBounds.set(magnifiedBounds); 501 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION); 502 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT); 503 504 if (accountedBounds.isRect()) { 505 Rect accountedFrame = mTempRect1; 506 accountedBounds.getBounds(accountedFrame); 507 if (accountedFrame.width() == screenWidth 508 && accountedFrame.height() == screenHeight) { 509 break; 510 } 511 } 512 } 513 514 visibleWindows.clear(); 515 516 magnifiedBounds.op(mHalfBorderWidth, mHalfBorderWidth, 517 screenWidth - mHalfBorderWidth, screenHeight - mHalfBorderWidth, 518 Region.Op.INTERSECT); 519 520 if (!mOldMagnifiedBounds.equals(magnifiedBounds)) { 521 Region bounds = Region.obtain(); 522 bounds.set(magnifiedBounds); 523 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, 524 bounds).sendToTarget(); 525 526 mWindow.setBounds(magnifiedBounds); 527 Rect dirtyRect = mTempRect1; 528 if (mFullRedrawNeeded) { 529 mFullRedrawNeeded = false; 530 dirtyRect.set(mHalfBorderWidth, mHalfBorderWidth, 531 screenWidth - mHalfBorderWidth, screenHeight - mHalfBorderWidth); 532 mWindow.invalidate(dirtyRect); 533 } else { 534 Region dirtyRegion = mTempRegion3; 535 dirtyRegion.set(magnifiedBounds); 536 dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION); 537 dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT); 538 dirtyRegion.getBounds(dirtyRect); 539 mWindow.invalidate(dirtyRect); 540 } 541 542 mOldMagnifiedBounds.set(magnifiedBounds); 543 } 544 } 545 546 public void onRotationChangedLocked() { 547 // If we are magnifying, hide the magnified border window immediately so 548 // the user does not see strange artifacts during rotation. The screenshot 549 // used for rotation has already the border. After the rotation is complete 550 // we will show the border. 551 if (isMagnifyingLocked()) { 552 setMagnifiedRegionBorderShownLocked(false, false); 553 final long delay = (long) (mLongAnimationDuration 554 * mWindowManagerService.getWindowAnimationScaleLocked()); 555 Message message = mHandler.obtainMessage( 556 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED); 557 mHandler.sendMessageDelayed(message, delay); 558 } 559 recomputeBoundsLocked(); 560 mWindow.updateSize(); 561 } 562 563 public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) { 564 if (shown) { 565 mFullRedrawNeeded = true; 566 mOldMagnifiedBounds.set(0, 0, 0, 0); 567 } 568 mWindow.setShown(shown, animate); 569 } 570 571 public void getMagnifiedFrameInContentCoordsLocked(Rect rect) { 572 MagnificationSpec spec = mMagnificationSpec; 573 mMagnifiedBounds.getBounds(rect); 574 rect.offset((int) -spec.offsetX, (int) -spec.offsetY); 575 rect.scale(1.0f / spec.scale); 576 } 577 578 public boolean isMagnifyingLocked() { 579 return mMagnificationSpec.scale > 1.0f; 580 } 581 582 public MagnificationSpec getMagnificationSpecLocked() { 583 return mMagnificationSpec; 584 } 585 586 /** NOTE: This has to be called within a surface transaction. */ 587 public void drawWindowIfNeededLocked() { 588 recomputeBoundsLocked(); 589 mWindow.drawIfNeeded(); 590 } 591 592 public void destroyWindow() { 593 mWindow.releaseSurface(); 594 } 595 596 private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) { 597 DisplayContent displayContent = mWindowManagerService 598 .getDefaultDisplayContentLocked(); 599 WindowList windowList = displayContent.getWindowList(); 600 final int windowCount = windowList.size(); 601 for (int i = 0; i < windowCount; i++) { 602 WindowState windowState = windowList.get(i); 603 if ((windowState.isOnScreen() || windowState.mAttrs.type == WindowManager 604 .LayoutParams.TYPE_UNIVERSE_BACKGROUND) 605 && !windowState.mWinAnimator.mEnterAnimationPending) { 606 outWindows.put(windowState.mLayer, windowState); 607 } 608 } 609 } 610 611 private final class ViewportWindow { 612 private static final String SURFACE_TITLE = "Magnification Overlay"; 613 614 private static final String PROPERTY_NAME_ALPHA = "alpha"; 615 616 private static final int MIN_ALPHA = 0; 617 private static final int MAX_ALPHA = 255; 618 619 private final Region mBounds = new Region(); 620 private final Rect mDirtyRect = new Rect(); 621 private final Paint mPaint = new Paint(); 622 623 private final ValueAnimator mShowHideFrameAnimator; 624 private final SurfaceControl mSurfaceControl; 625 private final Surface mSurface = new Surface(); 626 627 private boolean mShown; 628 private int mAlpha; 629 630 private boolean mInvalidated; 631 632 public ViewportWindow(Context context) { 633 SurfaceControl surfaceControl = null; 634 try { 635 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); 636 surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession, 637 SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT, 638 SurfaceControl.HIDDEN); 639 } catch (OutOfResourcesException oore) { 640 /* ignore */ 641 } 642 mSurfaceControl = surfaceControl; 643 mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay() 644 .getLayerStack()); 645 mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw( 646 WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) 647 * WindowManagerService.TYPE_LAYER_MULTIPLIER); 648 mSurfaceControl.setPosition(0, 0); 649 mSurface.copyFrom(mSurfaceControl); 650 651 TypedValue typedValue = new TypedValue(); 652 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight, 653 typedValue, true); 654 final int borderColor = context.getResources().getColor(typedValue.resourceId); 655 656 mPaint.setStyle(Paint.Style.STROKE); 657 mPaint.setStrokeWidth(mBorderWidth); 658 mPaint.setColor(borderColor); 659 660 Interpolator interpolator = new DecelerateInterpolator(2.5f); 661 final long longAnimationDuration = context.getResources().getInteger( 662 com.android.internal.R.integer.config_longAnimTime); 663 664 mShowHideFrameAnimator = ObjectAnimator.ofInt(this, PROPERTY_NAME_ALPHA, 665 MIN_ALPHA, MAX_ALPHA); 666 mShowHideFrameAnimator.setInterpolator(interpolator); 667 mShowHideFrameAnimator.setDuration(longAnimationDuration); 668 mInvalidated = true; 669 } 670 671 public void setShown(boolean shown, boolean animate) { 672 synchronized (mWindowManagerService.mWindowMap) { 673 if (mShown == shown) { 674 return; 675 } 676 mShown = shown; 677 if (animate) { 678 if (mShowHideFrameAnimator.isRunning()) { 679 mShowHideFrameAnimator.reverse(); 680 } else { 681 if (shown) { 682 mShowHideFrameAnimator.start(); 683 } else { 684 mShowHideFrameAnimator.reverse(); 685 } 686 } 687 } else { 688 mShowHideFrameAnimator.cancel(); 689 if (shown) { 690 setAlpha(MAX_ALPHA); 691 } else { 692 setAlpha(MIN_ALPHA); 693 } 694 } 695 if (DEBUG_VIEWPORT_WINDOW) { 696 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown); 697 } 698 } 699 } 700 701 @SuppressWarnings("unused") 702 // Called reflectively from an animator. 703 public int getAlpha() { 704 synchronized (mWindowManagerService.mWindowMap) { 705 return mAlpha; 706 } 707 } 708 709 public void setAlpha(int alpha) { 710 synchronized (mWindowManagerService.mWindowMap) { 711 if (mAlpha == alpha) { 712 return; 713 } 714 mAlpha = alpha; 715 invalidate(null); 716 if (DEBUG_VIEWPORT_WINDOW) { 717 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha); 718 } 719 } 720 } 721 722 public void setBounds(Region bounds) { 723 synchronized (mWindowManagerService.mWindowMap) { 724 if (mBounds.equals(bounds)) { 725 return; 726 } 727 mBounds.set(bounds); 728 invalidate(mDirtyRect); 729 if (DEBUG_VIEWPORT_WINDOW) { 730 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds); 731 } 732 } 733 } 734 735 public void updateSize() { 736 synchronized (mWindowManagerService.mWindowMap) { 737 mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); 738 mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y); 739 invalidate(mDirtyRect); 740 } 741 } 742 743 public void invalidate(Rect dirtyRect) { 744 if (dirtyRect != null) { 745 mDirtyRect.set(dirtyRect); 746 } else { 747 mDirtyRect.setEmpty(); 748 } 749 mInvalidated = true; 750 mWindowManagerService.scheduleAnimationLocked(); 751 } 752 753 /** NOTE: This has to be called within a surface transaction. */ 754 public void drawIfNeeded() { 755 synchronized (mWindowManagerService.mWindowMap) { 756 if (!mInvalidated) { 757 return; 758 } 759 mInvalidated = false; 760 Canvas canvas = null; 761 try { 762 // Empty dirty rectangle means unspecified. 763 if (mDirtyRect.isEmpty()) { 764 mBounds.getBounds(mDirtyRect); 765 } 766 mDirtyRect.inset(- mHalfBorderWidth, - mHalfBorderWidth); 767 canvas = mSurface.lockCanvas(mDirtyRect); 768 if (DEBUG_VIEWPORT_WINDOW) { 769 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect); 770 } 771 } catch (IllegalArgumentException iae) { 772 /* ignore */ 773 } catch (Surface.OutOfResourcesException oore) { 774 /* ignore */ 775 } 776 if (canvas == null) { 777 return; 778 } 779 if (DEBUG_VIEWPORT_WINDOW) { 780 Slog.i(LOG_TAG, "Bounds: " + mBounds); 781 } 782 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); 783 mPaint.setAlpha(mAlpha); 784 Path path = mBounds.getBoundaryPath(); 785 canvas.drawPath(path, mPaint); 786 787 mSurface.unlockCanvasAndPost(canvas); 788 789 if (mAlpha > 0) { 790 mSurfaceControl.show(); 791 } else { 792 mSurfaceControl.hide(); 793 } 794 } 795 } 796 797 public void releaseSurface() { 798 mSurfaceControl.release(); 799 mSurface.release(); 800 } 801 } 802 } 803 804 private class MyHandler extends Handler { 805 public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1; 806 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2; 807 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; 808 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4; 809 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5; 810 811 public MyHandler(Looper looper) { 812 super(looper); 813 } 814 815 @Override 816 public void handleMessage(Message message) { 817 switch (message.what) { 818 case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: { 819 Region bounds = (Region) message.obj; 820 mCallbacks.onMagnifedBoundsChanged(bounds); 821 bounds.recycle(); 822 } break; 823 824 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { 825 SomeArgs args = (SomeArgs) message.obj; 826 final int left = args.argi1; 827 final int top = args.argi2; 828 final int right = args.argi3; 829 final int bottom = args.argi4; 830 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom); 831 args.recycle(); 832 } break; 833 834 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: { 835 mCallbacks.onUserContextChanged(); 836 } break; 837 838 case MESSAGE_NOTIFY_ROTATION_CHANGED: { 839 final int rotation = message.arg1; 840 mCallbacks.onRotationChanged(rotation); 841 } break; 842 843 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : { 844 synchronized (mWindowManagerService.mWindowMap) { 845 if (mMagnifedViewport.isMagnifyingLocked()) { 846 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true); 847 mWindowManagerService.scheduleAnimationLocked(); 848 } 849 } 850 } break; 851 } 852 } 853 } 854 } 855 856 /** 857 * This class encapsulates the functionality related to computing the windows 858 * reported for accessibility purposes. These windows are all windows a sighted 859 * user can see on the screen. 860 */ 861 private static final class WindowsForAccessibilityObserver { 862 private static final String LOG_TAG = "WindowsForAccessibilityObserver"; 863 864 private static final boolean DEBUG = false; 865 866 private final SparseArray<WindowState> mTempWindowStates = 867 new SparseArray<WindowState>(); 868 869 private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>(); 870 871 private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>(); 872 873 private final RectF mTempRectF = new RectF(); 874 875 private final Matrix mTempMatrix = new Matrix(); 876 877 private final Point mTempPoint = new Point(); 878 879 private final Rect mTempRect = new Rect(); 880 881 private final Region mTempRegion = new Region(); 882 883 private final Region mTempRegion1 = new Region(); 884 885 private final Context mContext; 886 887 private final WindowManagerService mWindowManagerService; 888 889 private final Handler mHandler; 890 891 private final WindowsForAccessibilityCallback mCallback; 892 893 private final long mRecurringAccessibilityEventsIntervalMillis; 894 895 public WindowsForAccessibilityObserver(WindowManagerService windowManagerService, 896 WindowsForAccessibilityCallback callback) { 897 mContext = windowManagerService.mContext; 898 mWindowManagerService = windowManagerService; 899 mCallback = callback; 900 mHandler = new MyHandler(mWindowManagerService.mH.getLooper()); 901 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration 902 .getSendRecurringAccessibilityEventsInterval(); 903 computeChangedWindows(); 904 } 905 906 public void scheduleComputeChangedWindowsLocked() { 907 // If focus changed, compute changed windows immediately as the focused window 908 // is used by the accessibility manager service to determine the active window. 909 if (mWindowManagerService.mCurrentFocus != null 910 && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) { 911 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS); 912 computeChangedWindows(); 913 } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) { 914 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS, 915 mRecurringAccessibilityEventsIntervalMillis); 916 } 917 } 918 919 public void computeChangedWindows() { 920 if (DEBUG) { 921 Slog.i(LOG_TAG, "computeChangedWindows()"); 922 } 923 924 synchronized (mWindowManagerService.mWindowMap) { 925 // Do not send the windows if there is no current focus as 926 // the window manager is still looking for where to put it. 927 // We will do the work when we get a focus change callback. 928 if (mWindowManagerService.mCurrentFocus == null) { 929 return; 930 } 931 932 WindowManager windowManager = (WindowManager) 933 mContext.getSystemService(Context.WINDOW_SERVICE); 934 windowManager.getDefaultDisplay().getRealSize(mTempPoint); 935 final int screenWidth = mTempPoint.x; 936 final int screenHeight = mTempPoint.y; 937 938 Region unaccountedSpace = mTempRegion; 939 unaccountedSpace.set(0, 0, screenWidth, screenHeight); 940 941 SparseArray<WindowState> visibleWindows = mTempWindowStates; 942 populateVisibleWindowsOnScreenLocked(visibleWindows); 943 944 List<WindowInfo> windows = new ArrayList<WindowInfo>(); 945 946 Set<IBinder> addedWindows = mTempBinderSet; 947 addedWindows.clear(); 948 949 boolean focusedWindowAdded = false; 950 951 final int visibleWindowCount = visibleWindows.size(); 952 for (int i = visibleWindowCount - 1; i >= 0; i--) { 953 WindowState windowState = visibleWindows.valueAt(i); 954 955 // Compute the bounds in the screen. 956 Rect boundsInScreen = mTempRect; 957 computeWindowBoundsInScreen(windowState, boundsInScreen); 958 959 final int flags = windowState.mAttrs.flags; 960 961 // If the window is not touchable, do not report it but take into account 962 // the space it takes since the content behind it cannot be touched. 963 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { 964 continue; 965 } 966 967 // If the window is completely covered by other windows - ignore. 968 if (unaccountedSpace.quickReject(boundsInScreen)) { 969 continue; 970 } 971 972 // Add windows of certain types not covered by modal windows. 973 if (isReportedWindowType(windowState.mAttrs.type)) { 974 // Add the window to the ones to be reported. 975 WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen); 976 addedWindows.add(window.token); 977 windows.add(window); 978 if (windowState.isFocused()) { 979 focusedWindowAdded = true; 980 } 981 } 982 983 // Account for the space this window takes. 984 unaccountedSpace.op(boundsInScreen, unaccountedSpace, 985 Region.Op.REVERSE_DIFFERENCE); 986 987 // We figured out what is touchable for the entire screen - done. 988 if (unaccountedSpace.isEmpty()) { 989 break; 990 } 991 992 // If a window is modal, no other below can be touched - done. 993 if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 994 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) { 995 break; 996 } 997 } 998 999 // Always report the focused window. 1000 if (!focusedWindowAdded) { 1001 for (int i = visibleWindowCount - 1; i >= 0; i--) { 1002 WindowState windowState = visibleWindows.valueAt(i); 1003 if (windowState.isFocused()) { 1004 // Compute the bounds in the screen. 1005 Rect boundsInScreen = mTempRect; 1006 computeWindowBoundsInScreen(windowState, boundsInScreen); 1007 1008 // Add the window to the ones to be reported. 1009 WindowInfo window = obtainPopulatedWindowInfo(windowState, 1010 boundsInScreen); 1011 addedWindows.add(window.token); 1012 windows.add(window); 1013 break; 1014 } 1015 } 1016 } 1017 1018 // Remove child/parent references to windows that were not added. 1019 final int windowCount = windows.size(); 1020 for (int i = 0; i < windowCount; i++) { 1021 WindowInfo window = windows.get(i); 1022 if (!addedWindows.contains(window.parentToken)) { 1023 window.parentToken = null; 1024 } 1025 if (window.childTokens != null) { 1026 final int childTokenCount = window.childTokens.size(); 1027 for (int j = childTokenCount - 1; j >= 0; j--) { 1028 if (!addedWindows.contains(window.childTokens.get(j))) { 1029 window.childTokens.remove(j); 1030 } 1031 } 1032 // Leave the child token list if empty. 1033 } 1034 } 1035 1036 visibleWindows.clear(); 1037 addedWindows.clear(); 1038 1039 // We computed the windows and if they changed notify the client. 1040 boolean windowsChanged = false; 1041 if (mOldWindows.size() != windows.size()) { 1042 // Different size means something changed. 1043 windowsChanged = true; 1044 } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) { 1045 // Since we always traverse windows from high to low layer 1046 // the old and new windows at the same index should be the 1047 // same, otherwise something changed. 1048 for (int i = 0; i < windowCount; i++) { 1049 WindowInfo oldWindow = mOldWindows.get(i); 1050 WindowInfo newWindow = windows.get(i); 1051 // We do not care for layer changes given the window 1052 // order does not change. This brings no new information 1053 // to the clients. 1054 if (windowChangedNoLayer(oldWindow, newWindow)) { 1055 windowsChanged = true; 1056 break; 1057 } 1058 } 1059 } 1060 1061 if (windowsChanged) { 1062 if (DEBUG) { 1063 Log.i(LOG_TAG, "Windows changed:" + windows); 1064 } 1065 // Remember the old windows to detect changes. 1066 cacheWindows(windows); 1067 // Announce the change. 1068 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED, 1069 windows).sendToTarget(); 1070 } else { 1071 if (DEBUG) { 1072 Log.i(LOG_TAG, "No windows changed."); 1073 } 1074 // Recycle the nodes as we do not need them. 1075 clearAndRecycleWindows(windows); 1076 } 1077 } 1078 } 1079 1080 private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) { 1081 // Get the touchable frame. 1082 Region touchableRegion = mTempRegion1; 1083 windowState.getTouchableRegion(touchableRegion); 1084 Rect touchableFrame = mTempRect; 1085 touchableRegion.getBounds(touchableFrame); 1086 1087 // Move to origin as all transforms are captured by the matrix. 1088 RectF windowFrame = mTempRectF; 1089 windowFrame.set(touchableFrame); 1090 windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top); 1091 1092 // Map the frame to get what appears on the screen. 1093 Matrix matrix = mTempMatrix; 1094 populateTransformationMatrixLocked(windowState, matrix); 1095 matrix.mapRect(windowFrame); 1096 1097 // Got the bounds. 1098 outBounds.set((int) windowFrame.left, (int) windowFrame.top, 1099 (int) windowFrame.right, (int) windowFrame.bottom); 1100 } 1101 1102 private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState, 1103 Rect boundsInScreen) { 1104 WindowInfo window = WindowInfo.obtain(); 1105 window.type = windowState.mAttrs.type; 1106 window.layer = windowState.mLayer; 1107 window.token = windowState.mClient.asBinder(); 1108 1109 WindowState attachedWindow = windowState.mAttachedWindow; 1110 if (attachedWindow != null) { 1111 window.parentToken = attachedWindow.mClient.asBinder(); 1112 } 1113 1114 window.focused = windowState.isFocused(); 1115 window.boundsInScreen.set(boundsInScreen); 1116 1117 final int childCount = windowState.mChildWindows.size(); 1118 if (childCount > 0) { 1119 if (window.childTokens == null) { 1120 window.childTokens = new ArrayList<IBinder>(); 1121 } 1122 for (int j = 0; j < childCount; j++) { 1123 WindowState child = windowState.mChildWindows.get(j); 1124 window.childTokens.add(child.mClient.asBinder()); 1125 } 1126 } 1127 1128 return window; 1129 } 1130 1131 private void cacheWindows(List<WindowInfo> windows) { 1132 final int oldWindowCount = mOldWindows.size(); 1133 for (int i = oldWindowCount - 1; i >= 0; i--) { 1134 mOldWindows.remove(i).recycle(); 1135 } 1136 final int newWindowCount = windows.size(); 1137 for (int i = 0; i < newWindowCount; i++) { 1138 WindowInfo newWindow = windows.get(i); 1139 mOldWindows.add(WindowInfo.obtain(newWindow)); 1140 } 1141 } 1142 1143 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { 1144 if (oldWindow == newWindow) { 1145 return false; 1146 } 1147 if (oldWindow == null) { 1148 return true; 1149 } 1150 if (newWindow == null) { 1151 return true; 1152 } 1153 if (oldWindow.type != newWindow.type) { 1154 return true; 1155 } 1156 if (oldWindow.focused != newWindow.focused) { 1157 return true; 1158 } 1159 if (oldWindow.token == null) { 1160 if (newWindow.token != null) { 1161 return true; 1162 } 1163 } else if (!oldWindow.token.equals(newWindow.token)) { 1164 return true; 1165 } 1166 if (oldWindow.parentToken == null) { 1167 if (newWindow.parentToken != null) { 1168 return true; 1169 } 1170 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { 1171 return true; 1172 } 1173 if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) { 1174 return true; 1175 } 1176 if (oldWindow.childTokens != null && newWindow.childTokens != null 1177 && !oldWindow.childTokens.equals(newWindow.childTokens)) { 1178 return true; 1179 } 1180 return false; 1181 } 1182 1183 private void clearAndRecycleWindows(List<WindowInfo> windows) { 1184 final int windowCount = windows.size(); 1185 for (int i = windowCount - 1; i >= 0; i--) { 1186 windows.remove(i).recycle(); 1187 } 1188 } 1189 1190 private static boolean isReportedWindowType(int windowType) { 1191 return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM 1192 && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER 1193 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS 1194 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY 1195 && windowType != WindowManager.LayoutParams.TYPE_DRAG 1196 && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER 1197 && windowType != WindowManager.LayoutParams.TYPE_POINTER 1198 && windowType != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND 1199 && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY 1200 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY 1201 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY 1202 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION); 1203 } 1204 1205 private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) { 1206 DisplayContent displayContent = mWindowManagerService 1207 .getDefaultDisplayContentLocked(); 1208 WindowList windowList = displayContent.getWindowList(); 1209 final int windowCount = windowList.size(); 1210 for (int i = 0; i < windowCount; i++) { 1211 WindowState windowState = windowList.get(i); 1212 if (windowState.isVisibleLw()) { 1213 outWindows.put(windowState.mLayer, windowState); 1214 } 1215 } 1216 } 1217 1218 private class MyHandler extends Handler { 1219 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1; 1220 public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2; 1221 1222 public MyHandler(Looper looper) { 1223 super(looper, null, false); 1224 } 1225 1226 @Override 1227 @SuppressWarnings("unchecked") 1228 public void handleMessage(Message message) { 1229 switch (message.what) { 1230 case MESSAGE_COMPUTE_CHANGED_WINDOWS: { 1231 computeChangedWindows(); 1232 } break; 1233 1234 case MESSAGE_NOTIFY_WINDOWS_CHANGED: { 1235 List<WindowInfo> windows = (List<WindowInfo>) message.obj; 1236 mCallback.onWindowsForAccessibilityChanged(windows); 1237 clearAndRecycleWindows(windows); 1238 } break; 1239 } 1240 } 1241 } 1242 } 1243} 1244