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