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