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