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