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