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.os.Build.IS_USER; 20 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; 21 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; 22 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; 23 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 24 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; 25 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; 26 27 import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY; 28 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER; 29 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_H; 30 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_L; 31 import static com.android.server.accessibility.AccessibilityTraceProto.ACCESSIBILITY_SERVICE; 32 import static com.android.server.accessibility.AccessibilityTraceProto.CALENDAR_TIME; 33 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PARAMS; 34 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG; 35 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS; 36 import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS; 37 import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME; 38 import static com.android.server.accessibility.AccessibilityTraceProto.THREAD_ID_NAME; 39 import static com.android.server.accessibility.AccessibilityTraceProto.WHERE; 40 import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE; 41 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 42 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 43 import static com.android.server.wm.utils.RegionUtils.forEachRect; 44 45 import android.animation.ObjectAnimator; 46 import android.animation.ValueAnimator; 47 import android.annotation.NonNull; 48 import android.app.Application; 49 import android.content.Context; 50 import android.content.pm.PackageManagerInternal; 51 import android.graphics.BLASTBufferQueue; 52 import android.graphics.Canvas; 53 import android.graphics.Color; 54 import android.graphics.Matrix; 55 import android.graphics.Paint; 56 import android.graphics.Path; 57 import android.graphics.PixelFormat; 58 import android.graphics.Point; 59 import android.graphics.PorterDuff.Mode; 60 import android.graphics.Rect; 61 import android.graphics.RectF; 62 import android.graphics.Region; 63 import android.os.Binder; 64 import android.os.Build; 65 import android.os.Handler; 66 import android.os.HandlerThread; 67 import android.os.IBinder; 68 import android.os.Looper; 69 import android.os.Message; 70 import android.os.Process; 71 import android.os.SystemClock; 72 import android.util.ArraySet; 73 import android.util.IntArray; 74 import android.util.Slog; 75 import android.util.SparseArray; 76 import android.util.TypedValue; 77 import android.util.proto.ProtoOutputStream; 78 import android.view.Display; 79 import android.view.InsetsSource; 80 import android.view.MagnificationSpec; 81 import android.view.Surface; 82 import android.view.Surface.OutOfResourcesException; 83 import android.view.SurfaceControl; 84 import android.view.ViewConfiguration; 85 import android.view.WindowInfo; 86 import android.view.WindowManager; 87 import android.view.animation.DecelerateInterpolator; 88 import android.view.animation.Interpolator; 89 90 import com.android.internal.R; 91 import com.android.internal.os.SomeArgs; 92 import com.android.internal.util.TraceBuffer; 93 import com.android.server.LocalServices; 94 import com.android.server.policy.WindowManagerPolicy; 95 import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal; 96 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks; 97 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback; 98 99 import java.io.File; 100 import java.io.IOException; 101 import java.io.PrintWriter; 102 import java.nio.file.Files; 103 import java.nio.file.Paths; 104 import java.text.SimpleDateFormat; 105 import java.util.ArrayList; 106 import java.util.Arrays; 107 import java.util.Date; 108 import java.util.HashSet; 109 import java.util.List; 110 import java.util.Set; 111 112 /** 113 * This class contains the accessibility related logic of the window manager. 114 */ 115 final class AccessibilityController { 116 private static final String TAG = AccessibilityController.class.getSimpleName(); 117 118 private static final Object STATIC_LOCK = new Object(); 119 static AccessibilityControllerInternal getAccessibilityControllerInternal(WindowManagerService service)120 getAccessibilityControllerInternal(WindowManagerService service) { 121 return AccessibilityControllerInternalImpl.getInstance(service); 122 } 123 124 private final AccessibilityTracing mAccessibilityTracing; 125 private final WindowManagerService mService; 126 private static final Rect EMPTY_RECT = new Rect(); 127 private static final float[] sTempFloats = new float[9]; 128 AccessibilityController(WindowManagerService service)129 AccessibilityController(WindowManagerService service) { 130 mService = service; 131 mAccessibilityTracing = AccessibilityTracing.getInstance(service); 132 } 133 134 private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>(); 135 private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver = 136 new SparseArray<>(); 137 138 // Set to true if initializing window population complete. 139 private boolean mAllObserversInitialized = true; 140 setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks)141 boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) { 142 if (mAccessibilityTracing.isEnabled()) { 143 mAccessibilityTracing.logState( 144 TAG + ".setMagnificationCallbacks", 145 "displayId=" + displayId + "; callbacks={" + callbacks + "}"); 146 } 147 boolean result = false; 148 if (callbacks != null) { 149 if (mDisplayMagnifiers.get(displayId) != null) { 150 throw new IllegalStateException("Magnification callbacks already set!"); 151 } 152 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); 153 if (dc != null) { 154 final Display display = dc.getDisplay(); 155 if (display != null && display.getType() != Display.TYPE_OVERLAY) { 156 mDisplayMagnifiers.put(displayId, new DisplayMagnifier( 157 mService, dc, display, callbacks)); 158 result = true; 159 } 160 } 161 } else { 162 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 163 if (displayMagnifier == null) { 164 throw new IllegalStateException("Magnification callbacks already cleared!"); 165 } 166 displayMagnifier.destroy(); 167 mDisplayMagnifiers.remove(displayId); 168 result = true; 169 } 170 return result; 171 } 172 173 /** 174 * Sets a callback for observing which windows are touchable for the purposes 175 * of accessibility on specified display. 176 * 177 * @param displayId The logical display id. 178 * @param callback The callback. 179 * @return {@code false} if display id is not valid or an embedded display. 180 */ setWindowsForAccessibilityCallback(int displayId, WindowsForAccessibilityCallback callback)181 boolean setWindowsForAccessibilityCallback(int displayId, 182 WindowsForAccessibilityCallback callback) { 183 if (mAccessibilityTracing.isEnabled()) { 184 mAccessibilityTracing.logState( 185 TAG + ".setWindowsForAccessibilityCallback", 186 "displayId=" + displayId + "; callback={" + callback + "}"); 187 } 188 final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId); 189 if (dc == null) { 190 return false; 191 } 192 193 if (callback != null) { 194 WindowsForAccessibilityObserver observer = 195 mWindowsForAccessibilityObserver.get(displayId); 196 if (isEmbeddedDisplay(dc)) { 197 // If this display is an embedded one, its window observer should have been set from 198 // window manager after setting its parent window. But if its window observer is 199 // empty, that means this mapping didn't be set, and needs to do this again. 200 // This happened when accessibility window observer is disabled and enabled again. 201 if (observer == null) { 202 handleWindowObserverOfEmbeddedDisplay(displayId, dc.getParentWindow()); 203 } 204 return false; 205 } else if (observer != null) { 206 final String errorMessage = "Windows for accessibility callback of display " 207 + displayId + " already set!"; 208 Slog.e(TAG, errorMessage); 209 if (Build.IS_DEBUGGABLE) { 210 throw new IllegalStateException(errorMessage); 211 } 212 removeObserverOfEmbeddedDisplay(observer); 213 mWindowsForAccessibilityObserver.remove(displayId); 214 } 215 observer = new WindowsForAccessibilityObserver(mService, displayId, callback); 216 mWindowsForAccessibilityObserver.put(displayId, observer); 217 mAllObserversInitialized &= observer.mInitialized; 218 } else { 219 if (isEmbeddedDisplay(dc)) { 220 // If this display is an embedded one, its window observer should be removed along 221 // with the window observer of its parent display removed because the window 222 // observer of the embedded display and its parent display is the same, and would 223 // be removed together when stopping the window tracking of its parent display. So 224 // here don't need to do removing window observer of the embedded display again. 225 return true; 226 } 227 final WindowsForAccessibilityObserver windowsForA11yObserver = 228 mWindowsForAccessibilityObserver.get(displayId); 229 if (windowsForA11yObserver == null) { 230 final String errorMessage = "Windows for accessibility callback of display " 231 + displayId + " already cleared!"; 232 Slog.e(TAG, errorMessage); 233 if (Build.IS_DEBUGGABLE) { 234 throw new IllegalStateException(errorMessage); 235 } 236 } 237 removeObserverOfEmbeddedDisplay(windowsForA11yObserver); 238 mWindowsForAccessibilityObserver.remove(displayId); 239 } 240 return true; 241 } 242 performComputeChangedWindowsNot(int displayId, boolean forceSend)243 void performComputeChangedWindowsNot(int displayId, boolean forceSend) { 244 if (mAccessibilityTracing.isEnabled()) { 245 mAccessibilityTracing.logState( 246 TAG + ".performComputeChangedWindowsNot", 247 "displayId=" + displayId + "; forceSend=" + forceSend); 248 } 249 WindowsForAccessibilityObserver observer = null; 250 synchronized (mService.mGlobalLock) { 251 final WindowsForAccessibilityObserver windowsForA11yObserver = 252 mWindowsForAccessibilityObserver.get(displayId); 253 if (windowsForA11yObserver != null) { 254 observer = windowsForA11yObserver; 255 } 256 } 257 if (observer != null) { 258 observer.performComputeChangedWindows(forceSend); 259 } 260 } 261 setMagnificationSpec(int displayId, MagnificationSpec spec)262 void setMagnificationSpec(int displayId, MagnificationSpec spec) { 263 if (mAccessibilityTracing.isEnabled()) { 264 mAccessibilityTracing.logState(TAG + ".setMagnificationSpec", 265 "displayId=" + displayId + "; spec={" + spec + "}"); 266 } 267 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 268 if (displayMagnifier != null) { 269 displayMagnifier.setMagnificationSpec(spec); 270 } 271 final WindowsForAccessibilityObserver windowsForA11yObserver = 272 mWindowsForAccessibilityObserver.get(displayId); 273 if (windowsForA11yObserver != null) { 274 windowsForA11yObserver.scheduleComputeChangedWindows(); 275 } 276 } 277 getMagnificationRegion(int displayId, Region outMagnificationRegion)278 void getMagnificationRegion(int displayId, Region outMagnificationRegion) { 279 if (mAccessibilityTracing.isEnabled()) { 280 mAccessibilityTracing.logState(TAG + ".getMagnificationRegion", 281 "displayId=" + displayId + "; outMagnificationRegion={" + outMagnificationRegion 282 + "}"); 283 } 284 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 285 if (displayMagnifier != null) { 286 displayMagnifier.getMagnificationRegion(outMagnificationRegion); 287 } 288 } 289 onRectangleOnScreenRequested(int displayId, Rect rectangle)290 void onRectangleOnScreenRequested(int displayId, Rect rectangle) { 291 if (mAccessibilityTracing.isEnabled()) { 292 mAccessibilityTracing.logState( 293 TAG + ".onRectangleOnScreenRequested", 294 "displayId=" + displayId + "; rectangle={" + rectangle + "}"); 295 } 296 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 297 if (displayMagnifier != null) { 298 displayMagnifier.onRectangleOnScreenRequested(rectangle); 299 } 300 // Not relevant for the window observer. 301 } 302 onWindowLayersChanged(int displayId)303 void onWindowLayersChanged(int displayId) { 304 if (mAccessibilityTracing.isEnabled()) { 305 mAccessibilityTracing.logState( 306 TAG + ".onWindowLayersChanged", "displayId=" + displayId); 307 } 308 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 309 if (displayMagnifier != null) { 310 displayMagnifier.onWindowLayersChanged(); 311 } 312 final WindowsForAccessibilityObserver windowsForA11yObserver = 313 mWindowsForAccessibilityObserver.get(displayId); 314 if (windowsForA11yObserver != null) { 315 windowsForA11yObserver.scheduleComputeChangedWindows(); 316 } 317 } 318 onRotationChanged(DisplayContent displayContent)319 void onRotationChanged(DisplayContent displayContent) { 320 if (mAccessibilityTracing.isEnabled()) { 321 mAccessibilityTracing.logState(TAG + ".onRotationChanged", 322 "displayContent={" + displayContent + "}"); 323 } 324 final int displayId = displayContent.getDisplayId(); 325 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 326 if (displayMagnifier != null) { 327 displayMagnifier.onRotationChanged(displayContent); 328 } 329 final WindowsForAccessibilityObserver windowsForA11yObserver = 330 mWindowsForAccessibilityObserver.get(displayId); 331 if (windowsForA11yObserver != null) { 332 windowsForA11yObserver.scheduleComputeChangedWindows(); 333 } 334 } 335 onAppWindowTransition(int displayId, int transition)336 void onAppWindowTransition(int displayId, int transition) { 337 if (mAccessibilityTracing.isEnabled()) { 338 mAccessibilityTracing.logState(TAG + ".onAppWindowTransition", 339 "displayId=" + displayId + "; transition=" + transition); 340 } 341 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 342 if (displayMagnifier != null) { 343 displayMagnifier.onAppWindowTransition(displayId, transition); 344 } 345 // Not relevant for the window observer. 346 } 347 onWindowTransition(WindowState windowState, int transition)348 void onWindowTransition(WindowState windowState, int transition) { 349 if (mAccessibilityTracing.isEnabled()) { 350 mAccessibilityTracing.logState(TAG + ".onWindowTransition", 351 "windowState={" + windowState + "}; transition=" + transition); 352 } 353 final int displayId = windowState.getDisplayId(); 354 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 355 if (displayMagnifier != null) { 356 displayMagnifier.onWindowTransition(windowState, transition); 357 } 358 final WindowsForAccessibilityObserver windowsForA11yObserver = 359 mWindowsForAccessibilityObserver.get(displayId); 360 if (windowsForA11yObserver != null) { 361 windowsForA11yObserver.scheduleComputeChangedWindows(); 362 } 363 } 364 onWindowFocusChangedNot(int displayId)365 void onWindowFocusChangedNot(int displayId) { 366 // Not relevant for the display magnifier. 367 if (mAccessibilityTracing.isEnabled()) { 368 mAccessibilityTracing.logState( 369 TAG + ".onWindowFocusChangedNot", "displayId=" + displayId); 370 } 371 WindowsForAccessibilityObserver observer = null; 372 synchronized (mService.mGlobalLock) { 373 final WindowsForAccessibilityObserver windowsForA11yObserver = 374 mWindowsForAccessibilityObserver.get(displayId); 375 if (windowsForA11yObserver != null) { 376 observer = windowsForA11yObserver; 377 } 378 } 379 if (observer != null) { 380 observer.performComputeChangedWindows(false); 381 } 382 // Since we abandon initializing observers if no window has focus, make sure all observers 383 // are initialized. 384 sendCallbackToUninitializedObserversIfNeeded(); 385 } 386 sendCallbackToUninitializedObserversIfNeeded()387 private void sendCallbackToUninitializedObserversIfNeeded() { 388 List<WindowsForAccessibilityObserver> unInitializedObservers; 389 synchronized (mService.mGlobalLock) { 390 if (mAllObserversInitialized) { 391 return; 392 } 393 if (mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus == null) { 394 return; 395 } 396 unInitializedObservers = new ArrayList<>(); 397 for (int i = mWindowsForAccessibilityObserver.size() - 1; i >= 0; --i) { 398 final WindowsForAccessibilityObserver observer = 399 mWindowsForAccessibilityObserver.valueAt(i); 400 if (!observer.mInitialized) { 401 unInitializedObservers.add(observer); 402 } 403 } 404 // Reset the flag to record the new added observer. 405 mAllObserversInitialized = true; 406 } 407 408 boolean areAllObserversInitialized = true; 409 for (int i = unInitializedObservers.size() - 1; i >= 0; --i) { 410 final WindowsForAccessibilityObserver observer = unInitializedObservers.get(i); 411 observer.performComputeChangedWindows(true); 412 areAllObserversInitialized &= observer.mInitialized; 413 } 414 synchronized (mService.mGlobalLock) { 415 mAllObserversInitialized &= areAllObserversInitialized; 416 } 417 } 418 419 /** 420 * Called when the location or the size of the window is changed. Moving the window to 421 * another display is also taken into consideration. 422 * @param displayIds the display ids of displays when the situation happens. 423 */ onSomeWindowResizedOrMoved(int... displayIds)424 void onSomeWindowResizedOrMoved(int... displayIds) { 425 onSomeWindowResizedOrMovedWithCallingUid(Binder.getCallingUid(), displayIds); 426 } 427 onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds)428 void onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds) { 429 if (mAccessibilityTracing.isEnabled()) { 430 mAccessibilityTracing.logState( 431 TAG + ".onSomeWindowResizedOrMoved", 432 "displayIds={" + displayIds.toString() + "}", 433 "".getBytes(), 434 callingUid); 435 } 436 // Not relevant for the display magnifier. 437 for (int i = 0; i < displayIds.length; i++) { 438 final WindowsForAccessibilityObserver windowsForA11yObserver = 439 mWindowsForAccessibilityObserver.get(displayIds[i]); 440 if (windowsForA11yObserver != null) { 441 windowsForA11yObserver.scheduleComputeChangedWindows(); 442 } 443 } 444 } 445 drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t)446 void drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t) { 447 if (mAccessibilityTracing.isEnabled()) { 448 mAccessibilityTracing.logState( 449 TAG + ".drawMagnifiedRegionBorderIfNeeded", 450 "displayId=" + displayId + "; transaction={" + t + "}"); 451 } 452 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 453 if (displayMagnifier != null) { 454 displayMagnifier.drawMagnifiedRegionBorderIfNeeded(t); 455 } 456 // Not relevant for the window observer. 457 } 458 getMagnificationSpecForWindow(WindowState windowState)459 MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) { 460 if (mAccessibilityTracing.isEnabled()) { 461 mAccessibilityTracing.logState(TAG + ".getMagnificationSpecForWindow", 462 "windowState={" + windowState + "}"); 463 } 464 final int displayId = windowState.getDisplayId(); 465 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 466 if (displayMagnifier != null) { 467 return displayMagnifier.getMagnificationSpecForWindow(windowState); 468 } 469 return null; 470 } 471 hasCallbacks()472 boolean hasCallbacks() { 473 if (mAccessibilityTracing.isEnabled()) { 474 mAccessibilityTracing.logState(TAG + ".hasCallbacks"); 475 } 476 return (mDisplayMagnifiers.size() > 0 477 || mWindowsForAccessibilityObserver.size() > 0); 478 } 479 setForceShowMagnifiableBounds(int displayId, boolean show)480 void setForceShowMagnifiableBounds(int displayId, boolean show) { 481 if (mAccessibilityTracing.isEnabled()) { 482 mAccessibilityTracing.logState(TAG + ".setForceShowMagnifiableBounds", 483 "displayId=" + displayId + "; show=" + show); 484 } 485 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 486 if (displayMagnifier != null) { 487 displayMagnifier.setForceShowMagnifiableBounds(show); 488 displayMagnifier.showMagnificationBoundsIfNeeded(); 489 } 490 } 491 handleWindowObserverOfEmbeddedDisplay(int embeddedDisplayId, WindowState parentWindow)492 void handleWindowObserverOfEmbeddedDisplay(int embeddedDisplayId, 493 WindowState parentWindow) { 494 handleWindowObserverOfEmbeddedDisplay( 495 embeddedDisplayId, parentWindow, Binder.getCallingUid()); 496 } 497 handleWindowObserverOfEmbeddedDisplay( int embeddedDisplayId, WindowState parentWindow, int callingUid)498 void handleWindowObserverOfEmbeddedDisplay( 499 int embeddedDisplayId, WindowState parentWindow, int callingUid) { 500 if (mAccessibilityTracing.isEnabled()) { 501 mAccessibilityTracing.logState(TAG + ".handleWindowObserverOfEmbeddedDisplay", 502 "embeddedDisplayId=" + embeddedDisplayId + "; parentWindowState={" 503 + parentWindow + "}", 504 "".getBytes(), 505 callingUid); 506 } 507 if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) { 508 return; 509 } 510 // Finds the parent display of this embedded display 511 final int parentDisplayId; 512 WindowState candidate = parentWindow; 513 while (candidate != null) { 514 parentWindow = candidate; 515 candidate = parentWindow.getDisplayContent().getParentWindow(); 516 } 517 parentDisplayId = parentWindow.getDisplayId(); 518 // Uses the observer of parent display 519 final WindowsForAccessibilityObserver windowsForA11yObserver = 520 mWindowsForAccessibilityObserver.get(parentDisplayId); 521 522 if (windowsForA11yObserver != null) { 523 windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId); 524 // Replaces the observer of embedded display to the one of parent display 525 mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver); 526 } 527 } 528 onImeSurfaceShownChanged(WindowState windowState, boolean shown)529 void onImeSurfaceShownChanged(WindowState windowState, boolean shown) { 530 if (mAccessibilityTracing.isEnabled()) { 531 mAccessibilityTracing.logState(TAG + ".onImeSurfaceShownChanged", 532 "windowState=" + windowState + "; shown=" + shown); 533 } 534 final int displayId = windowState.getDisplayId(); 535 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); 536 if (displayMagnifier != null) { 537 displayMagnifier.onImeSurfaceShownChanged(shown); 538 } 539 } 540 populateTransformationMatrix(WindowState windowState, Matrix outMatrix)541 private static void populateTransformationMatrix(WindowState windowState, 542 Matrix outMatrix) { 543 windowState.getTransformationMatrix(sTempFloats, outMatrix); 544 } 545 dump(PrintWriter pw, String prefix)546 void dump(PrintWriter pw, String prefix) { 547 for (int i = 0; i < mDisplayMagnifiers.size(); i++) { 548 final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.valueAt(i); 549 if (displayMagnifier != null) { 550 displayMagnifier.dump(pw, prefix 551 + "Magnification display# " + mDisplayMagnifiers.keyAt(i)); 552 } 553 } 554 pw.println(prefix 555 + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver); 556 } 557 removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver observerOfParentDisplay)558 private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver 559 observerOfParentDisplay) { 560 final IntArray embeddedDisplayIdList = 561 observerOfParentDisplay.getAndClearEmbeddedDisplayIdList(); 562 563 for (int index = 0; index < embeddedDisplayIdList.size(); index++) { 564 final int embeddedDisplayId = embeddedDisplayIdList.get(index); 565 mWindowsForAccessibilityObserver.remove(embeddedDisplayId); 566 } 567 } 568 isEmbeddedDisplay(DisplayContent dc)569 private static boolean isEmbeddedDisplay(DisplayContent dc) { 570 final Display display = dc.getDisplay(); 571 572 return display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null; 573 } 574 575 /** 576 * This class encapsulates the functionality related to display magnification. 577 */ 578 private static final class DisplayMagnifier { 579 580 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM; 581 582 private static final boolean DEBUG_WINDOW_TRANSITIONS = false; 583 private static final boolean DEBUG_ROTATION = false; 584 private static final boolean DEBUG_LAYERS = false; 585 private static final boolean DEBUG_RECTANGLE_REQUESTED = false; 586 private static final boolean DEBUG_VIEWPORT_WINDOW = false; 587 588 private final Rect mTempRect1 = new Rect(); 589 private final Rect mTempRect2 = new Rect(); 590 591 private final Region mTempRegion1 = new Region(); 592 private final Region mTempRegion2 = new Region(); 593 private final Region mTempRegion3 = new Region(); 594 private final Region mTempRegion4 = new Region(); 595 596 private final Context mDisplayContext; 597 private final WindowManagerService mService; 598 private final MagnifiedViewport mMagnifedViewport; 599 private final Handler mHandler; 600 private final DisplayContent mDisplayContent; 601 private final Display mDisplay; 602 private final AccessibilityTracing mAccessibilityTracing; 603 604 private final MagnificationCallbacks mCallbacks; 605 606 private final long mLongAnimationDuration; 607 608 private boolean mForceShowMagnifiableBounds = false; 609 DisplayMagnifier(WindowManagerService windowManagerService, DisplayContent displayContent, Display display, MagnificationCallbacks callbacks)610 DisplayMagnifier(WindowManagerService windowManagerService, 611 DisplayContent displayContent, 612 Display display, 613 MagnificationCallbacks callbacks) { 614 mDisplayContext = windowManagerService.mContext.createDisplayContext(display); 615 mService = windowManagerService; 616 mCallbacks = callbacks; 617 mDisplayContent = displayContent; 618 mDisplay = display; 619 mHandler = new MyHandler(mService.mH.getLooper()); 620 mMagnifedViewport = new MagnifiedViewport(); 621 mAccessibilityTracing = AccessibilityTracing.getInstance(mService); 622 mLongAnimationDuration = mDisplayContext.getResources().getInteger( 623 com.android.internal.R.integer.config_longAnimTime); 624 if (mAccessibilityTracing.isEnabled()) { 625 mAccessibilityTracing.logState(LOG_TAG + ".DisplayMagnifier.constructor", 626 "windowManagerService={" + windowManagerService + "}; displayContent={" 627 + displayContent + "}; display={" + display + "}; callbacks={" 628 + callbacks + "}"); 629 } 630 } 631 setMagnificationSpec(MagnificationSpec spec)632 void setMagnificationSpec(MagnificationSpec spec) { 633 if (mAccessibilityTracing.isEnabled()) { 634 mAccessibilityTracing.logState( 635 LOG_TAG + ".setMagnificationSpec", "spec={" + spec + "}"); 636 } 637 mMagnifedViewport.updateMagnificationSpec(spec); 638 mMagnifedViewport.recomputeBounds(); 639 640 mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec); 641 mService.scheduleAnimationLocked(); 642 } 643 setForceShowMagnifiableBounds(boolean show)644 void setForceShowMagnifiableBounds(boolean show) { 645 if (mAccessibilityTracing.isEnabled()) { 646 mAccessibilityTracing.logState( 647 LOG_TAG + ".setForceShowMagnifiableBounds", "show=" + show); 648 } 649 mForceShowMagnifiableBounds = show; 650 mMagnifedViewport.setMagnifiedRegionBorderShown(show, true); 651 } 652 isForceShowingMagnifiableBounds()653 boolean isForceShowingMagnifiableBounds() { 654 if (mAccessibilityTracing.isEnabled()) { 655 mAccessibilityTracing.logState(LOG_TAG + ".isForceShowingMagnifiableBounds"); 656 } 657 return mForceShowMagnifiableBounds; 658 } 659 onRectangleOnScreenRequested(Rect rectangle)660 void onRectangleOnScreenRequested(Rect rectangle) { 661 if (mAccessibilityTracing.isEnabled()) { 662 mAccessibilityTracing.logState( 663 LOG_TAG + ".onRectangleOnScreenRequested", "rectangle={" + rectangle + "}"); 664 } 665 if (DEBUG_RECTANGLE_REQUESTED) { 666 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle); 667 } 668 if (!mMagnifedViewport.isMagnifying()) { 669 return; 670 } 671 Rect magnifiedRegionBounds = mTempRect2; 672 mMagnifedViewport.getMagnifiedFrameInContentCoords(magnifiedRegionBounds); 673 if (magnifiedRegionBounds.contains(rectangle)) { 674 return; 675 } 676 SomeArgs args = SomeArgs.obtain(); 677 args.argi1 = rectangle.left; 678 args.argi2 = rectangle.top; 679 args.argi3 = rectangle.right; 680 args.argi4 = rectangle.bottom; 681 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, 682 args).sendToTarget(); 683 } 684 onWindowLayersChanged()685 void onWindowLayersChanged() { 686 if (mAccessibilityTracing.isEnabled()) { 687 mAccessibilityTracing.logState(LOG_TAG + ".onWindowLayersChanged"); 688 } 689 if (DEBUG_LAYERS) { 690 Slog.i(LOG_TAG, "Layers changed."); 691 } 692 mMagnifedViewport.recomputeBounds(); 693 mService.scheduleAnimationLocked(); 694 } 695 onRotationChanged(DisplayContent displayContent)696 void onRotationChanged(DisplayContent displayContent) { 697 if (mAccessibilityTracing.isEnabled()) { 698 mAccessibilityTracing.logState( 699 LOG_TAG + ".onRotationChanged", "displayContent={" + displayContent + "}"); 700 } 701 if (DEBUG_ROTATION) { 702 final int rotation = displayContent.getRotation(); 703 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation) 704 + " displayId: " + displayContent.getDisplayId()); 705 } 706 mMagnifedViewport.onRotationChanged(); 707 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED); 708 } 709 onAppWindowTransition(int displayId, int transition)710 void onAppWindowTransition(int displayId, int transition) { 711 if (mAccessibilityTracing.isEnabled()) { 712 mAccessibilityTracing.logState(LOG_TAG + ".onAppWindowTransition", 713 "displayId=" + displayId + "; transition=" + transition); 714 } 715 if (DEBUG_WINDOW_TRANSITIONS) { 716 Slog.i(LOG_TAG, "Window transition: " 717 + AppTransition.appTransitionOldToString(transition) 718 + " displayId: " + displayId); 719 } 720 final boolean magnifying = mMagnifedViewport.isMagnifying(); 721 if (magnifying) { 722 switch (transition) { 723 case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN: 724 case WindowManager.TRANSIT_OLD_TASK_OPEN: 725 case WindowManager.TRANSIT_OLD_TASK_TO_FRONT: 726 case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN: 727 case WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE: 728 case WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN: { 729 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED); 730 } 731 } 732 } 733 } 734 onWindowTransition(WindowState windowState, int transition)735 void onWindowTransition(WindowState windowState, int transition) { 736 if (mAccessibilityTracing.isEnabled()) { 737 mAccessibilityTracing.logState(LOG_TAG + ".onWindowTransition", 738 "windowState={" + windowState + "}; transition=" + transition); 739 } 740 if (DEBUG_WINDOW_TRANSITIONS) { 741 Slog.i(LOG_TAG, "Window transition: " 742 + AppTransition.appTransitionOldToString(transition) 743 + " displayId: " + windowState.getDisplayId()); 744 } 745 final boolean magnifying = mMagnifedViewport.isMagnifying(); 746 final int type = windowState.mAttrs.type; 747 switch (transition) { 748 case WindowManagerPolicy.TRANSIT_ENTER: 749 case WindowManagerPolicy.TRANSIT_SHOW: { 750 if (!magnifying) { 751 break; 752 } 753 switch (type) { 754 case WindowManager.LayoutParams.TYPE_APPLICATION: 755 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: 756 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: 757 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: 758 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: 759 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: 760 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: 761 case WindowManager.LayoutParams.TYPE_SEARCH_BAR: 762 case WindowManager.LayoutParams.TYPE_PHONE: 763 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: 764 case WindowManager.LayoutParams.TYPE_TOAST: 765 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: 766 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: 767 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: 768 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: 769 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: 770 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: 771 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: 772 case WindowManager.LayoutParams.TYPE_QS_DIALOG: 773 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: { 774 Rect magnifiedRegionBounds = mTempRect2; 775 mMagnifedViewport.getMagnifiedFrameInContentCoords( 776 magnifiedRegionBounds); 777 Rect touchableRegionBounds = mTempRect1; 778 windowState.getTouchableRegion(mTempRegion1); 779 mTempRegion1.getBounds(touchableRegionBounds); 780 if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) { 781 mCallbacks.onRectangleOnScreenRequested( 782 touchableRegionBounds.left, 783 touchableRegionBounds.top, 784 touchableRegionBounds.right, 785 touchableRegionBounds.bottom); 786 } 787 } break; 788 } break; 789 } 790 } 791 } 792 onImeSurfaceShownChanged(boolean shown)793 void onImeSurfaceShownChanged(boolean shown) { 794 if (mAccessibilityTracing.isEnabled()) { 795 mAccessibilityTracing.logState( 796 LOG_TAG + ".onImeSurfaceShownChanged", "shown=" + shown); 797 } 798 mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED, 799 shown ? 1 : 0, 0).sendToTarget(); 800 } 801 getMagnificationSpecForWindow(WindowState windowState)802 MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) { 803 if (mAccessibilityTracing.isEnabled()) { 804 mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationSpecForWindow", 805 "windowState={" + windowState + "}"); 806 } 807 MagnificationSpec spec = mMagnifedViewport.getMagnificationSpec(); 808 if (spec != null && !spec.isNop()) { 809 if (!windowState.shouldMagnify()) { 810 return null; 811 } 812 } 813 return spec; 814 } 815 getMagnificationRegion(Region outMagnificationRegion)816 void getMagnificationRegion(Region outMagnificationRegion) { 817 if (mAccessibilityTracing.isEnabled()) { 818 mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationRegion", 819 "outMagnificationRegion={" + outMagnificationRegion + "}"); 820 } 821 // Make sure we're working with the most current bounds 822 mMagnifedViewport.recomputeBounds(); 823 mMagnifedViewport.getMagnificationRegion(outMagnificationRegion); 824 } 825 destroy()826 void destroy() { 827 if (mAccessibilityTracing.isEnabled()) { 828 mAccessibilityTracing.logState(LOG_TAG + ".destroy"); 829 } 830 mMagnifedViewport.destroyWindow(); 831 } 832 833 // Can be called outside of a surface transaction showMagnificationBoundsIfNeeded()834 void showMagnificationBoundsIfNeeded() { 835 if (mAccessibilityTracing.isEnabled()) { 836 mAccessibilityTracing.logState(LOG_TAG + ".showMagnificationBoundsIfNeeded"); 837 } 838 mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED) 839 .sendToTarget(); 840 } 841 drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t)842 void drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t) { 843 if (mAccessibilityTracing.isEnabled()) { 844 mAccessibilityTracing.logState(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded", 845 "transition={" + t + "}"); 846 } 847 mMagnifedViewport.drawWindowIfNeeded(t); 848 } 849 dump(PrintWriter pw, String prefix)850 void dump(PrintWriter pw, String prefix) { 851 mMagnifedViewport.dump(pw, prefix); 852 } 853 854 private final class MagnifiedViewport { 855 856 private final SparseArray<WindowState> mTempWindowStates = 857 new SparseArray<WindowState>(); 858 859 private final RectF mTempRectF = new RectF(); 860 861 private final Point mScreenSize = new Point(); 862 863 private final Matrix mTempMatrix = new Matrix(); 864 865 private final Region mMagnificationRegion = new Region(); 866 private final Region mOldMagnificationRegion = new Region(); 867 868 private final Path mCircularPath; 869 870 private final MagnificationSpec mMagnificationSpec = new MagnificationSpec(); 871 872 private final float mBorderWidth; 873 private final int mHalfBorderWidth; 874 private final int mDrawBorderInset; 875 876 private final ViewportWindow mWindow; 877 878 private boolean mFullRedrawNeeded; 879 private int mTempLayer = 0; 880 MagnifiedViewport()881 MagnifiedViewport() { 882 mBorderWidth = mDisplayContext.getResources().getDimension( 883 com.android.internal.R.dimen.accessibility_magnification_indicator_width); 884 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2); 885 mDrawBorderInset = (int) mBorderWidth / 2; 886 mWindow = new ViewportWindow(mDisplayContext); 887 888 if (mDisplayContext.getResources().getConfiguration().isScreenRound()) { 889 mCircularPath = new Path(); 890 mDisplay.getRealSize(mScreenSize); 891 final int centerXY = mScreenSize.x / 2; 892 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW); 893 } else { 894 mCircularPath = null; 895 } 896 897 recomputeBounds(); 898 } 899 getMagnificationRegion(@onNull Region outMagnificationRegion)900 void getMagnificationRegion(@NonNull Region outMagnificationRegion) { 901 outMagnificationRegion.set(mMagnificationRegion); 902 } 903 updateMagnificationSpec(MagnificationSpec spec)904 void updateMagnificationSpec(MagnificationSpec spec) { 905 if (spec != null) { 906 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY); 907 } else { 908 mMagnificationSpec.clear(); 909 } 910 // If this message is pending we are in a rotation animation and do not want 911 // to show the border. We will do so when the pending message is handled. 912 if (!mHandler.hasMessages( 913 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) { 914 setMagnifiedRegionBorderShown( 915 isMagnifying() || isForceShowingMagnifiableBounds(), true); 916 } 917 } 918 recomputeBounds()919 void recomputeBounds() { 920 mDisplay.getRealSize(mScreenSize); 921 final int screenWidth = mScreenSize.x; 922 final int screenHeight = mScreenSize.y; 923 924 mMagnificationRegion.set(0, 0, 0, 0); 925 final Region availableBounds = mTempRegion1; 926 availableBounds.set(0, 0, screenWidth, screenHeight); 927 928 if (mCircularPath != null) { 929 availableBounds.setPath(mCircularPath, availableBounds); 930 } 931 932 Region nonMagnifiedBounds = mTempRegion4; 933 nonMagnifiedBounds.set(0, 0, 0, 0); 934 935 SparseArray<WindowState> visibleWindows = mTempWindowStates; 936 visibleWindows.clear(); 937 populateWindowsOnScreen(visibleWindows); 938 939 final int visibleWindowCount = visibleWindows.size(); 940 for (int i = visibleWindowCount - 1; i >= 0; i--) { 941 WindowState windowState = visibleWindows.valueAt(i); 942 final int windowType = windowState.mAttrs.type; 943 if (isExcludedWindowType(windowType) 944 || ((windowState.mAttrs.privateFlags 945 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) { 946 continue; 947 } 948 949 // Consider the touchable portion of the window 950 Matrix matrix = mTempMatrix; 951 populateTransformationMatrix(windowState, matrix); 952 Region touchableRegion = mTempRegion3; 953 windowState.getTouchableRegion(touchableRegion); 954 Rect touchableFrame = mTempRect1; 955 touchableRegion.getBounds(touchableFrame); 956 RectF windowFrame = mTempRectF; 957 windowFrame.set(touchableFrame); 958 windowFrame.offset(-windowState.getFrame().left, 959 -windowState.getFrame().top); 960 matrix.mapRect(windowFrame); 961 Region windowBounds = mTempRegion2; 962 windowBounds.set((int) windowFrame.left, (int) windowFrame.top, 963 (int) windowFrame.right, (int) windowFrame.bottom); 964 // Only update new regions 965 Region portionOfWindowAlreadyAccountedFor = mTempRegion3; 966 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion); 967 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION); 968 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE); 969 970 if (windowState.shouldMagnify()) { 971 mMagnificationRegion.op(windowBounds, Region.Op.UNION); 972 mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT); 973 } else { 974 nonMagnifiedBounds.op(windowBounds, Region.Op.UNION); 975 availableBounds.op(windowBounds, Region.Op.DIFFERENCE); 976 } 977 978 // If the navigation bar window doesn't have touchable region, count 979 // navigation bar insets into nonMagnifiedBounds. It happens when 980 // navigation mode is gestural. 981 if (isUntouchableNavigationBar(windowState, mTempRegion3)) { 982 final Rect navBarInsets = getNavBarInsets(mDisplayContent); 983 nonMagnifiedBounds.op(navBarInsets, Region.Op.UNION); 984 availableBounds.op(navBarInsets, Region.Op.DIFFERENCE); 985 } 986 987 // Count letterbox into nonMagnifiedBounds 988 if (windowState.areAppWindowBoundsLetterboxed()) { 989 Region letterboxBounds = getLetterboxBounds(windowState); 990 nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION); 991 availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE); 992 } 993 994 // Update accounted bounds 995 Region accountedBounds = mTempRegion2; 996 accountedBounds.set(mMagnificationRegion); 997 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION); 998 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT); 999 1000 if (accountedBounds.isRect()) { 1001 Rect accountedFrame = mTempRect1; 1002 accountedBounds.getBounds(accountedFrame); 1003 if (accountedFrame.width() == screenWidth 1004 && accountedFrame.height() == screenHeight) { 1005 break; 1006 } 1007 } 1008 } 1009 1010 visibleWindows.clear(); 1011 1012 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset, 1013 screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset, 1014 Region.Op.INTERSECT); 1015 1016 final boolean magnifiedChanged = 1017 !mOldMagnificationRegion.equals(mMagnificationRegion); 1018 if (magnifiedChanged) { 1019 mWindow.setBounds(mMagnificationRegion); 1020 final Rect dirtyRect = mTempRect1; 1021 if (mFullRedrawNeeded) { 1022 mFullRedrawNeeded = false; 1023 dirtyRect.set(mDrawBorderInset, mDrawBorderInset, 1024 screenWidth - mDrawBorderInset, 1025 screenHeight - mDrawBorderInset); 1026 mWindow.invalidate(dirtyRect); 1027 } else { 1028 final Region dirtyRegion = mTempRegion3; 1029 dirtyRegion.set(mMagnificationRegion); 1030 dirtyRegion.op(mOldMagnificationRegion, Region.Op.XOR); 1031 dirtyRegion.getBounds(dirtyRect); 1032 mWindow.invalidate(dirtyRect); 1033 } 1034 1035 mOldMagnificationRegion.set(mMagnificationRegion); 1036 final SomeArgs args = SomeArgs.obtain(); 1037 args.arg1 = Region.obtain(mMagnificationRegion); 1038 mHandler.obtainMessage( 1039 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args) 1040 .sendToTarget(); 1041 } 1042 } 1043 isExcludedWindowType(int windowType)1044 private boolean isExcludedWindowType(int windowType) { 1045 return windowType == TYPE_MAGNIFICATION_OVERLAY 1046 // Omit the touch region to avoid the cut out of the magnification 1047 // bounds because nav bar panel is unmagnifiable. 1048 || windowType == TYPE_NAVIGATION_BAR_PANEL 1049 // Omit the touch region of window magnification to avoid the cut out of the 1050 // magnification and the magnified center of window magnification could be 1051 // in the bounds 1052 || windowType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; 1053 } 1054 onRotationChanged()1055 void onRotationChanged() { 1056 // If we are showing the magnification border, hide it immediately so 1057 // the user does not see strange artifacts during rotation. The screenshot 1058 // used for rotation already has the border. After the rotation is complete 1059 // we will show the border. 1060 if (isMagnifying() || isForceShowingMagnifiableBounds()) { 1061 setMagnifiedRegionBorderShown(false, false); 1062 final long delay = (long) (mLongAnimationDuration 1063 * mService.getWindowAnimationScaleLocked()); 1064 Message message = mHandler.obtainMessage( 1065 MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED); 1066 mHandler.sendMessageDelayed(message, delay); 1067 } 1068 recomputeBounds(); 1069 mWindow.updateSize(); 1070 } 1071 setMagnifiedRegionBorderShown(boolean shown, boolean animate)1072 void setMagnifiedRegionBorderShown(boolean shown, boolean animate) { 1073 if (shown) { 1074 mFullRedrawNeeded = true; 1075 mOldMagnificationRegion.set(0, 0, 0, 0); 1076 } 1077 mWindow.setShown(shown, animate); 1078 } 1079 getMagnifiedFrameInContentCoords(Rect rect)1080 void getMagnifiedFrameInContentCoords(Rect rect) { 1081 MagnificationSpec spec = mMagnificationSpec; 1082 mMagnificationRegion.getBounds(rect); 1083 rect.offset((int) -spec.offsetX, (int) -spec.offsetY); 1084 rect.scale(1.0f / spec.scale); 1085 } 1086 isMagnifying()1087 boolean isMagnifying() { 1088 return mMagnificationSpec.scale > 1.0f; 1089 } 1090 getMagnificationSpec()1091 MagnificationSpec getMagnificationSpec() { 1092 return mMagnificationSpec; 1093 } 1094 drawWindowIfNeeded(SurfaceControl.Transaction t)1095 void drawWindowIfNeeded(SurfaceControl.Transaction t) { 1096 recomputeBounds(); 1097 mWindow.drawIfNeeded(t); 1098 } 1099 destroyWindow()1100 void destroyWindow() { 1101 mWindow.releaseSurface(); 1102 } 1103 populateWindowsOnScreen(SparseArray<WindowState> outWindows)1104 private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) { 1105 mTempLayer = 0; 1106 mDisplayContent.forAllWindows((w) -> { 1107 if (w.isOnScreen() && w.isVisible() 1108 && (w.mAttrs.alpha != 0)) { 1109 mTempLayer++; 1110 outWindows.put(mTempLayer, w); 1111 } 1112 }, false /* traverseTopToBottom */ ); 1113 } 1114 dump(PrintWriter pw, String prefix)1115 void dump(PrintWriter pw, String prefix) { 1116 mWindow.dump(pw, prefix); 1117 } 1118 1119 private final class ViewportWindow { 1120 private static final String SURFACE_TITLE = "Magnification Overlay"; 1121 1122 private final Region mBounds = new Region(); 1123 private final Rect mDirtyRect = new Rect(); 1124 private final Paint mPaint = new Paint(); 1125 1126 private final SurfaceControl mSurfaceControl; 1127 private final BLASTBufferQueue mBlastBufferQueue; 1128 private final Surface mSurface; 1129 1130 private final AnimationController mAnimationController; 1131 1132 private boolean mShown; 1133 private int mAlpha; 1134 1135 private boolean mInvalidated; 1136 ViewportWindow(Context context)1137 ViewportWindow(Context context) { 1138 SurfaceControl surfaceControl = null; 1139 try { 1140 surfaceControl = mDisplayContent 1141 .makeOverlay() 1142 .setName(SURFACE_TITLE) 1143 .setBLASTLayer() 1144 .setFormat(PixelFormat.TRANSLUCENT) 1145 .setCallsite("ViewportWindow") 1146 .build(); 1147 } catch (OutOfResourcesException oore) { 1148 /* ignore */ 1149 } 1150 mSurfaceControl = surfaceControl; 1151 mDisplay.getRealSize(mScreenSize); 1152 mBlastBufferQueue = new BLASTBufferQueue(SURFACE_TITLE, mSurfaceControl, 1153 mScreenSize.x, mScreenSize.y, PixelFormat.RGBA_8888); 1154 1155 final SurfaceControl.Transaction t = mService.mTransactionFactory.get(); 1156 final int layer = 1157 mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) * 1158 WindowManagerService.TYPE_LAYER_MULTIPLIER; 1159 t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0); 1160 InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t, 1161 mDisplayContent.getDisplayId(), "Magnification Overlay"); 1162 t.apply(); 1163 mSurface = mBlastBufferQueue.createSurface(); 1164 1165 mAnimationController = new AnimationController(context, 1166 mService.mH.getLooper()); 1167 1168 TypedValue typedValue = new TypedValue(); 1169 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight, 1170 typedValue, true); 1171 final int borderColor = context.getColor(typedValue.resourceId); 1172 1173 mPaint.setStyle(Paint.Style.STROKE); 1174 mPaint.setStrokeWidth(mBorderWidth); 1175 mPaint.setColor(borderColor); 1176 1177 mInvalidated = true; 1178 } 1179 setShown(boolean shown, boolean animate)1180 void setShown(boolean shown, boolean animate) { 1181 synchronized (mService.mGlobalLock) { 1182 if (mShown == shown) { 1183 return; 1184 } 1185 mShown = shown; 1186 mAnimationController.onFrameShownStateChanged(shown, animate); 1187 if (DEBUG_VIEWPORT_WINDOW) { 1188 Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown); 1189 } 1190 } 1191 } 1192 1193 @SuppressWarnings("unused") 1194 // Called reflectively from an animator. getAlpha()1195 int getAlpha() { 1196 synchronized (mService.mGlobalLock) { 1197 return mAlpha; 1198 } 1199 } 1200 setAlpha(int alpha)1201 void setAlpha(int alpha) { 1202 synchronized (mService.mGlobalLock) { 1203 if (mAlpha == alpha) { 1204 return; 1205 } 1206 mAlpha = alpha; 1207 invalidate(null); 1208 if (DEBUG_VIEWPORT_WINDOW) { 1209 Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha); 1210 } 1211 } 1212 } 1213 setBounds(Region bounds)1214 void setBounds(Region bounds) { 1215 synchronized (mService.mGlobalLock) { 1216 if (mBounds.equals(bounds)) { 1217 return; 1218 } 1219 mBounds.set(bounds); 1220 invalidate(mDirtyRect); 1221 if (DEBUG_VIEWPORT_WINDOW) { 1222 Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds); 1223 } 1224 } 1225 } 1226 updateSize()1227 void updateSize() { 1228 synchronized (mService.mGlobalLock) { 1229 mDisplay.getRealSize(mScreenSize); 1230 mBlastBufferQueue.update(mSurfaceControl, mScreenSize.x, mScreenSize.y, 1231 PixelFormat.RGBA_8888); 1232 invalidate(mDirtyRect); 1233 } 1234 } 1235 invalidate(Rect dirtyRect)1236 void invalidate(Rect dirtyRect) { 1237 if (dirtyRect != null) { 1238 mDirtyRect.set(dirtyRect); 1239 } else { 1240 mDirtyRect.setEmpty(); 1241 } 1242 mInvalidated = true; 1243 mService.scheduleAnimationLocked(); 1244 } 1245 drawIfNeeded(SurfaceControl.Transaction t)1246 void drawIfNeeded(SurfaceControl.Transaction t) { 1247 synchronized (mService.mGlobalLock) { 1248 if (!mInvalidated) { 1249 return; 1250 } 1251 mInvalidated = false; 1252 if (mAlpha > 0) { 1253 Canvas canvas = null; 1254 try { 1255 // Empty dirty rectangle means unspecified. 1256 if (mDirtyRect.isEmpty()) { 1257 mBounds.getBounds(mDirtyRect); 1258 } 1259 mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth); 1260 canvas = mSurface.lockCanvas(mDirtyRect); 1261 if (DEBUG_VIEWPORT_WINDOW) { 1262 Slog.i(LOG_TAG, "Dirty rect: " + mDirtyRect); 1263 } 1264 } catch (IllegalArgumentException iae) { 1265 /* ignore */ 1266 } catch (Surface.OutOfResourcesException oore) { 1267 /* ignore */ 1268 } 1269 if (canvas == null) { 1270 return; 1271 } 1272 if (DEBUG_VIEWPORT_WINDOW) { 1273 Slog.i(LOG_TAG, "Bounds: " + mBounds); 1274 } 1275 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); 1276 mPaint.setAlpha(mAlpha); 1277 Path path = mBounds.getBoundaryPath(); 1278 canvas.drawPath(path, mPaint); 1279 1280 mSurface.unlockCanvasAndPost(canvas); 1281 t.show(mSurfaceControl); 1282 } else { 1283 t.hide(mSurfaceControl); 1284 } 1285 } 1286 } 1287 releaseSurface()1288 void releaseSurface() { 1289 if (mBlastBufferQueue != null) { 1290 mBlastBufferQueue.destroy(); 1291 } 1292 mService.mTransactionFactory.get().remove(mSurfaceControl).apply(); 1293 mSurface.release(); 1294 } 1295 dump(PrintWriter pw, String prefix)1296 void dump(PrintWriter pw, String prefix) { 1297 pw.println(prefix 1298 + " mBounds= " + mBounds 1299 + " mDirtyRect= " + mDirtyRect 1300 + " mWidth= " + mScreenSize.x 1301 + " mHeight= " + mScreenSize.y); 1302 } 1303 1304 private final class AnimationController extends Handler { 1305 private static final String PROPERTY_NAME_ALPHA = "alpha"; 1306 1307 private static final int MIN_ALPHA = 0; 1308 private static final int MAX_ALPHA = 255; 1309 1310 private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1; 1311 1312 private final ValueAnimator mShowHideFrameAnimator; 1313 AnimationController(Context context, Looper looper)1314 AnimationController(Context context, Looper looper) { 1315 super(looper); 1316 mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this, 1317 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA); 1318 1319 Interpolator interpolator = new DecelerateInterpolator(2.5f); 1320 final long longAnimationDuration = context.getResources().getInteger( 1321 com.android.internal.R.integer.config_longAnimTime); 1322 1323 mShowHideFrameAnimator.setInterpolator(interpolator); 1324 mShowHideFrameAnimator.setDuration(longAnimationDuration); 1325 } 1326 onFrameShownStateChanged(boolean shown, boolean animate)1327 void onFrameShownStateChanged(boolean shown, boolean animate) { 1328 obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED, 1329 shown ? 1 : 0, animate ? 1 : 0).sendToTarget(); 1330 } 1331 1332 @Override handleMessage(Message message)1333 public void handleMessage(Message message) { 1334 switch (message.what) { 1335 case MSG_FRAME_SHOWN_STATE_CHANGED: { 1336 final boolean shown = message.arg1 == 1; 1337 final boolean animate = message.arg2 == 1; 1338 1339 if (animate) { 1340 if (mShowHideFrameAnimator.isRunning()) { 1341 mShowHideFrameAnimator.reverse(); 1342 } else { 1343 if (shown) { 1344 mShowHideFrameAnimator.start(); 1345 } else { 1346 mShowHideFrameAnimator.reverse(); 1347 } 1348 } 1349 } else { 1350 mShowHideFrameAnimator.cancel(); 1351 if (shown) { 1352 setAlpha(MAX_ALPHA); 1353 } else { 1354 setAlpha(MIN_ALPHA); 1355 } 1356 } 1357 } break; 1358 } 1359 } 1360 } 1361 } 1362 } 1363 1364 private class MyHandler extends Handler { 1365 public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1; 1366 public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2; 1367 public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; 1368 public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4; 1369 public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5; 1370 public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6; 1371 MyHandler(Looper looper)1372 MyHandler(Looper looper) { 1373 super(looper); 1374 } 1375 1376 @Override handleMessage(Message message)1377 public void handleMessage(Message message) { 1378 switch (message.what) { 1379 case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: { 1380 final SomeArgs args = (SomeArgs) message.obj; 1381 final Region magnifiedBounds = (Region) args.arg1; 1382 mCallbacks.onMagnificationRegionChanged(magnifiedBounds); 1383 magnifiedBounds.recycle(); 1384 } break; 1385 1386 case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { 1387 SomeArgs args = (SomeArgs) message.obj; 1388 final int left = args.argi1; 1389 final int top = args.argi2; 1390 final int right = args.argi3; 1391 final int bottom = args.argi4; 1392 mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom); 1393 args.recycle(); 1394 } break; 1395 1396 case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: { 1397 mCallbacks.onUserContextChanged(); 1398 } break; 1399 1400 case MESSAGE_NOTIFY_ROTATION_CHANGED: { 1401 final int rotation = message.arg1; 1402 mCallbacks.onRotationChanged(rotation); 1403 } break; 1404 1405 case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : { 1406 synchronized (mService.mGlobalLock) { 1407 if (mMagnifedViewport.isMagnifying() 1408 || isForceShowingMagnifiableBounds()) { 1409 mMagnifedViewport.setMagnifiedRegionBorderShown(true, true); 1410 mService.scheduleAnimationLocked(); 1411 } 1412 } 1413 } break; 1414 1415 case MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED: { 1416 final boolean shown = message.arg1 == 1; 1417 mCallbacks.onImeWindowVisibilityChanged(shown); 1418 } break; 1419 } 1420 } 1421 } 1422 } 1423 isUntouchableNavigationBar(WindowState windowState, Region touchableRegion)1424 static boolean isUntouchableNavigationBar(WindowState windowState, 1425 Region touchableRegion) { 1426 if (windowState.mAttrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR) { 1427 return false; 1428 } 1429 1430 // Gets the touchable region. 1431 windowState.getTouchableRegion(touchableRegion); 1432 1433 return touchableRegion.isEmpty(); 1434 } 1435 getNavBarInsets(DisplayContent displayContent)1436 static Rect getNavBarInsets(DisplayContent displayContent) { 1437 final InsetsSource source = displayContent.getInsetsStateController().getRawInsetsState() 1438 .peekSource(ITYPE_NAVIGATION_BAR); 1439 return source != null ? source.getFrame() : EMPTY_RECT; 1440 } 1441 getLetterboxBounds(WindowState windowState)1442 static Region getLetterboxBounds(WindowState windowState) { 1443 final ActivityRecord appToken = windowState.mActivityRecord; 1444 if (appToken == null) { 1445 return new Region(); 1446 } 1447 final Rect letterboxInsets = appToken.getLetterboxInsets(); 1448 final Rect nonLetterboxRect = windowState.getBounds(); 1449 nonLetterboxRect.inset(letterboxInsets); 1450 final Region letterboxBounds = new Region(); 1451 letterboxBounds.set(windowState.getBounds()); 1452 letterboxBounds.op(nonLetterboxRect, Region.Op.DIFFERENCE); 1453 return letterboxBounds; 1454 } 1455 1456 /** 1457 * This class encapsulates the functionality related to computing the windows 1458 * reported for accessibility purposes. These windows are all windows a sighted 1459 * user can see on the screen. 1460 */ 1461 private static final class WindowsForAccessibilityObserver { 1462 private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? 1463 "WindowsForAccessibilityObserver" : TAG_WM; 1464 1465 private static final boolean DEBUG = false; 1466 1467 private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>(); 1468 1469 private final Set<IBinder> mTempBinderSet = new ArraySet<>(); 1470 1471 private final RectF mTempRectF = new RectF(); 1472 1473 private final Matrix mTempMatrix = new Matrix(); 1474 1475 private final Point mTempPoint = new Point(); 1476 1477 private final Region mTempRegion = new Region(); 1478 1479 private final Region mTempRegion1 = new Region(); 1480 1481 private final WindowManagerService mService; 1482 1483 private final Handler mHandler; 1484 1485 private final AccessibilityTracing mAccessibilityTracing; 1486 1487 private final WindowsForAccessibilityCallback mCallback; 1488 1489 private final int mDisplayId; 1490 1491 private final long mRecurringAccessibilityEventsIntervalMillis; 1492 1493 private final IntArray mEmbeddedDisplayIdList = new IntArray(0); 1494 1495 // Set to true if initializing window population complete. 1496 private boolean mInitialized; 1497 WindowsForAccessibilityObserver(WindowManagerService windowManagerService, int displayId, WindowsForAccessibilityCallback callback)1498 WindowsForAccessibilityObserver(WindowManagerService windowManagerService, 1499 int displayId, 1500 WindowsForAccessibilityCallback callback) { 1501 mService = windowManagerService; 1502 mCallback = callback; 1503 mDisplayId = displayId; 1504 mHandler = new MyHandler(mService.mH.getLooper()); 1505 mAccessibilityTracing = AccessibilityTracing.getInstance(mService); 1506 mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration 1507 .getSendRecurringAccessibilityEventsInterval(); 1508 computeChangedWindows(true); 1509 } 1510 performComputeChangedWindows(boolean forceSend)1511 void performComputeChangedWindows(boolean forceSend) { 1512 if (mAccessibilityTracing.isEnabled()) { 1513 mAccessibilityTracing.logState(LOG_TAG + ".performComputeChangedWindows", 1514 "forceSend=" + forceSend); 1515 } 1516 mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS); 1517 computeChangedWindows(forceSend); 1518 } 1519 scheduleComputeChangedWindows()1520 void scheduleComputeChangedWindows() { 1521 if (mAccessibilityTracing.isEnabled()) { 1522 mAccessibilityTracing.logState(LOG_TAG + ".scheduleComputeChangedWindows"); 1523 } 1524 if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) { 1525 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS, 1526 mRecurringAccessibilityEventsIntervalMillis); 1527 } 1528 } 1529 getAndClearEmbeddedDisplayIdList()1530 IntArray getAndClearEmbeddedDisplayIdList() { 1531 final IntArray returnedArray = new IntArray(mEmbeddedDisplayIdList.size()); 1532 returnedArray.addAll(mEmbeddedDisplayIdList); 1533 mEmbeddedDisplayIdList.clear(); 1534 1535 return returnedArray; 1536 } 1537 addEmbeddedDisplay(int displayId)1538 void addEmbeddedDisplay(int displayId) { 1539 if (displayId == mDisplayId) { 1540 return; 1541 } 1542 mEmbeddedDisplayIdList.add(displayId); 1543 } 1544 shellRootIsAbove(WindowState windowState, ShellRoot shellRoot)1545 boolean shellRootIsAbove(WindowState windowState, ShellRoot shellRoot) { 1546 int wsLayer = mService.mPolicy.getWindowLayerLw(windowState); 1547 int shellLayer = mService.mPolicy.getWindowLayerFromTypeLw(shellRoot.getWindowType(), 1548 true); 1549 return shellLayer >= wsLayer; 1550 } 1551 addShellRootsIfAbove(WindowState windowState, ArrayList<ShellRoot> shellRoots, int shellRootIndex, List<WindowInfo> windows, Set<IBinder> addedWindows, Region unaccountedSpace, boolean focusedWindowAdded)1552 int addShellRootsIfAbove(WindowState windowState, ArrayList<ShellRoot> shellRoots, 1553 int shellRootIndex, List<WindowInfo> windows, Set<IBinder> addedWindows, 1554 Region unaccountedSpace, boolean focusedWindowAdded) { 1555 while (shellRootIndex < shellRoots.size() 1556 && shellRootIsAbove(windowState, shellRoots.get(shellRootIndex))) { 1557 ShellRoot shellRoot = shellRoots.get(shellRootIndex); 1558 shellRootIndex++; 1559 final WindowInfo info = shellRoot.getWindowInfo(); 1560 if (info == null) { 1561 continue; 1562 } 1563 1564 info.layer = addedWindows.size(); 1565 windows.add(info); 1566 addedWindows.add(info.token); 1567 unaccountedSpace.op(info.regionInScreen, unaccountedSpace, 1568 Region.Op.REVERSE_DIFFERENCE); 1569 if (unaccountedSpace.isEmpty() && focusedWindowAdded) { 1570 break; 1571 } 1572 } 1573 return shellRootIndex; 1574 } 1575 getSortedShellRoots( SparseArray<ShellRoot> originalShellRoots)1576 private ArrayList<ShellRoot> getSortedShellRoots( 1577 SparseArray<ShellRoot> originalShellRoots) { 1578 ArrayList<ShellRoot> sortedShellRoots = new ArrayList<>(originalShellRoots.size()); 1579 for (int i = originalShellRoots.size() - 1; i >= 0; --i) { 1580 sortedShellRoots.add(originalShellRoots.valueAt(i)); 1581 } 1582 1583 sortedShellRoots.sort((left, right) -> 1584 mService.mPolicy.getWindowLayerFromTypeLw(right.getWindowType(), true) 1585 - mService.mPolicy.getWindowLayerFromTypeLw(left.getWindowType(), 1586 true)); 1587 1588 return sortedShellRoots; 1589 } 1590 1591 /** 1592 * Check if windows have changed, and send them to the accessibility subsystem if they have. 1593 * 1594 * @param forceSend Send the windows the accessibility even if they haven't changed. 1595 */ computeChangedWindows(boolean forceSend)1596 void computeChangedWindows(boolean forceSend) { 1597 if (mAccessibilityTracing.isEnabled()) { 1598 mAccessibilityTracing.logState( 1599 LOG_TAG + ".computeChangedWindows", "forceSend=" + forceSend); 1600 } 1601 if (DEBUG) { 1602 Slog.i(LOG_TAG, "computeChangedWindows()"); 1603 } 1604 1605 List<WindowInfo> windows = new ArrayList<>(); 1606 final int topFocusedDisplayId; 1607 IBinder topFocusedWindowToken = null; 1608 1609 synchronized (mService.mGlobalLock) { 1610 // If there is a recents animation running, then use the animation target as the 1611 // top window state. Otherwise,do not send the windows if there is no top focus as 1612 // the window manager is still looking for where to put it. We will do the work when 1613 // we get a focus change callback. 1614 final RecentsAnimationController controller = 1615 mService.getRecentsAnimationController(); 1616 final WindowState topFocusedWindowState = controller != null 1617 ? controller.getTargetAppMainWindow() 1618 : getTopFocusWindow(); 1619 if (topFocusedWindowState == null) { 1620 if (DEBUG) { 1621 Slog.d(LOG_TAG, "top focused window is null, compute it again later"); 1622 } 1623 return; 1624 } 1625 1626 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); 1627 if (dc == null) { 1628 //It should not happen because it is created while adding the callback. 1629 Slog.w(LOG_TAG, "display content is null, should be created later"); 1630 return; 1631 } 1632 final Display display = dc.getDisplay(); 1633 display.getRealSize(mTempPoint); 1634 final int screenWidth = mTempPoint.x; 1635 final int screenHeight = mTempPoint.y; 1636 1637 Region unaccountedSpace = mTempRegion; 1638 unaccountedSpace.set(0, 0, screenWidth, screenHeight); 1639 1640 final SparseArray<WindowState> visibleWindows = mTempWindowStates; 1641 populateVisibleWindowsOnScreen(visibleWindows); 1642 Set<IBinder> addedWindows = mTempBinderSet; 1643 addedWindows.clear(); 1644 1645 boolean focusedWindowAdded = false; 1646 1647 final int visibleWindowCount = visibleWindows.size(); 1648 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>(); 1649 1650 ArrayList<ShellRoot> shellRoots = getSortedShellRoots(dc.mShellRoots); 1651 1652 // Iterate until we figure out what is touchable for the entire screen. 1653 int shellRootIndex = 0; 1654 for (int i = visibleWindowCount - 1; i >= 0; i--) { 1655 final WindowState windowState = visibleWindows.valueAt(i); 1656 int prevShellRootIndex = shellRootIndex; 1657 shellRootIndex = addShellRootsIfAbove(windowState, shellRoots, shellRootIndex, 1658 windows, addedWindows, unaccountedSpace, focusedWindowAdded); 1659 1660 // If a Shell Root was added, it could have accounted for all the space already. 1661 if (shellRootIndex > prevShellRootIndex && unaccountedSpace.isEmpty() 1662 && focusedWindowAdded) { 1663 break; 1664 } 1665 1666 final Region regionInScreen = new Region(); 1667 computeWindowRegionInScreen(windowState, regionInScreen); 1668 1669 if (windowMattersToAccessibility(windowState, regionInScreen, unaccountedSpace, 1670 skipRemainingWindowsForTasks)) { 1671 addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows); 1672 updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace, 1673 skipRemainingWindowsForTasks); 1674 focusedWindowAdded |= windowState.isFocused(); 1675 } else if (isUntouchableNavigationBar(windowState, mTempRegion1)) { 1676 // If this widow is navigation bar without touchable region, accounting the 1677 // region of navigation bar inset because all touch events from this region 1678 // would be received by launcher, i.e. this region is a un-touchable one 1679 // for the application. 1680 unaccountedSpace.op(getNavBarInsets(dc), unaccountedSpace, 1681 Region.Op.REVERSE_DIFFERENCE); 1682 } 1683 1684 if (unaccountedSpace.isEmpty() && focusedWindowAdded) { 1685 break; 1686 } 1687 } 1688 1689 // Remove child/parent references to windows that were not added. 1690 final int windowCount = windows.size(); 1691 for (int i = 0; i < windowCount; i++) { 1692 WindowInfo window = windows.get(i); 1693 if (!addedWindows.contains(window.parentToken)) { 1694 window.parentToken = null; 1695 } 1696 if (window.childTokens != null) { 1697 final int childTokenCount = window.childTokens.size(); 1698 for (int j = childTokenCount - 1; j >= 0; j--) { 1699 if (!addedWindows.contains(window.childTokens.get(j))) { 1700 window.childTokens.remove(j); 1701 } 1702 } 1703 // Leave the child token list if empty. 1704 } 1705 } 1706 1707 visibleWindows.clear(); 1708 addedWindows.clear(); 1709 1710 // Gets the top focused display Id and window token for supporting multi-display. 1711 // If this top focused display is an embedded one, using its parent display as the 1712 // top focused display. 1713 final DisplayContent topFocusedDisplayContent = 1714 mService.mRoot.getTopFocusedDisplayContent(); 1715 topFocusedDisplayId = isEmbeddedDisplay(topFocusedDisplayContent) ? mDisplayId 1716 : topFocusedDisplayContent.getDisplayId(); 1717 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder(); 1718 } 1719 mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId, 1720 topFocusedWindowToken, windows); 1721 1722 // Recycle the windows as we do not need them. 1723 clearAndRecycleWindows(windows); 1724 mInitialized = true; 1725 } 1726 windowMattersToAccessibility(WindowState windowState, Region regionInScreen, Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks)1727 private boolean windowMattersToAccessibility(WindowState windowState, 1728 Region regionInScreen, Region unaccountedSpace, 1729 HashSet<Integer> skipRemainingWindowsForTasks) { 1730 final RecentsAnimationController controller = mService.getRecentsAnimationController(); 1731 if (controller != null && controller.shouldIgnoreForAccessibility(windowState)) { 1732 return false; 1733 } 1734 1735 if (windowState.isFocused()) { 1736 return true; 1737 } 1738 1739 // If the window is part of a task that we're finished with - ignore. 1740 final Task task = windowState.getTask(); 1741 if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) { 1742 return false; 1743 } 1744 1745 // Ignore non-touchable windows, except the split-screen divider, which is 1746 // occasionally non-touchable but still useful for identifying split-screen 1747 // mode. 1748 if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) 1749 && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) { 1750 return false; 1751 } 1752 1753 // If the window is completely covered by other windows - ignore. 1754 if (unaccountedSpace.quickReject(regionInScreen)) { 1755 return false; 1756 } 1757 1758 // Add windows of certain types not covered by modal windows. 1759 if (isReportedWindowType(windowState.mAttrs.type)) { 1760 return true; 1761 } 1762 1763 return false; 1764 } 1765 updateUnaccountedSpace(WindowState windowState, Region regionInScreen, Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks)1766 private void updateUnaccountedSpace(WindowState windowState, Region regionInScreen, 1767 Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) { 1768 if (windowState.mAttrs.type 1769 != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) { 1770 1771 // Account for the space this window takes if the window 1772 // is not an accessibility overlay which does not change 1773 // the reported windows. 1774 unaccountedSpace.op(regionInScreen, unaccountedSpace, 1775 Region.Op.REVERSE_DIFFERENCE); 1776 1777 // If a window is modal it prevents other windows from being touched 1778 if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1779 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) { 1780 if (!windowState.hasTapExcludeRegion()) { 1781 // Account for all space in the task, whether the windows in it are 1782 // touchable or not. The modal window blocks all touches from the task's 1783 // area. 1784 unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace, 1785 Region.Op.REVERSE_DIFFERENCE); 1786 } else { 1787 // If a window has tap exclude region, we need to account it. 1788 final Region displayRegion = new Region(windowState.getDisplayFrame()); 1789 final Region tapExcludeRegion = new Region(); 1790 windowState.getTapExcludeRegion(tapExcludeRegion); 1791 displayRegion.op(tapExcludeRegion, displayRegion, 1792 Region.Op.REVERSE_DIFFERENCE); 1793 unaccountedSpace.op(displayRegion, unaccountedSpace, 1794 Region.Op.REVERSE_DIFFERENCE); 1795 } 1796 1797 final Task task = windowState.getTask(); 1798 if (task != null) { 1799 // If the window is associated with a particular task, we can skip the 1800 // rest of the windows for that task. 1801 skipRemainingWindowsForTasks.add(task.mTaskId); 1802 } else if (!windowState.hasTapExcludeRegion()) { 1803 // If the window is not associated with a particular task, then it is 1804 // globally modal. In this case we can skip all remaining windows when 1805 // it doesn't has tap exclude region. 1806 unaccountedSpace.setEmpty(); 1807 } 1808 } 1809 1810 // Account for the space of letterbox. 1811 if (windowState.areAppWindowBoundsLetterboxed()) { 1812 unaccountedSpace.op(getLetterboxBounds(windowState), unaccountedSpace, 1813 Region.Op.REVERSE_DIFFERENCE); 1814 } 1815 } 1816 } 1817 computeWindowRegionInScreen(WindowState windowState, Region outRegion)1818 private void computeWindowRegionInScreen(WindowState windowState, Region outRegion) { 1819 // Get the touchable frame. 1820 Region touchableRegion = mTempRegion1; 1821 windowState.getTouchableRegion(touchableRegion); 1822 1823 // Map the frame to get what appears on the screen. 1824 Matrix matrix = mTempMatrix; 1825 populateTransformationMatrix(windowState, matrix); 1826 1827 forEachRect(touchableRegion, rect -> { 1828 // Move to origin as all transforms are captured by the matrix. 1829 RectF windowFrame = mTempRectF; 1830 windowFrame.set(rect); 1831 windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top); 1832 1833 matrix.mapRect(windowFrame); 1834 1835 // Union all rects. 1836 outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top, 1837 (int) windowFrame.right, (int) windowFrame.bottom)); 1838 }); 1839 } 1840 addPopulatedWindowInfo(WindowState windowState, Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut)1841 private static void addPopulatedWindowInfo(WindowState windowState, Region regionInScreen, 1842 List<WindowInfo> out, Set<IBinder> tokenOut) { 1843 final WindowInfo window = windowState.getWindowInfo(); 1844 window.regionInScreen.set(regionInScreen); 1845 window.layer = tokenOut.size(); 1846 out.add(window); 1847 tokenOut.add(window.token); 1848 } 1849 clearAndRecycleWindows(List<WindowInfo> windows)1850 private static void clearAndRecycleWindows(List<WindowInfo> windows) { 1851 final int windowCount = windows.size(); 1852 for (int i = windowCount - 1; i >= 0; i--) { 1853 windows.remove(i).recycle(); 1854 } 1855 } 1856 isReportedWindowType(int windowType)1857 private static boolean isReportedWindowType(int windowType) { 1858 return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER 1859 && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS 1860 && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY 1861 && windowType != WindowManager.LayoutParams.TYPE_DRAG 1862 && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER 1863 && windowType != WindowManager.LayoutParams.TYPE_POINTER 1864 && windowType != TYPE_MAGNIFICATION_OVERLAY 1865 && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY 1866 && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY 1867 && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION); 1868 } 1869 populateVisibleWindowsOnScreen(SparseArray<WindowState> outWindows)1870 private void populateVisibleWindowsOnScreen(SparseArray<WindowState> outWindows) { 1871 final List<WindowState> tempWindowStatesList = new ArrayList<>(); 1872 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); 1873 if (dc == null) { 1874 return; 1875 } 1876 1877 dc.forAllWindows(w -> { 1878 if (w.isVisible()) { 1879 tempWindowStatesList.add(w); 1880 } 1881 }, false /* traverseTopToBottom */); 1882 // Insert the re-parented windows in another display below their parents in 1883 // default display. 1884 mService.mRoot.forAllWindows(w -> { 1885 final WindowState parentWindow = findRootDisplayParentWindow(w); 1886 if (parentWindow == null) { 1887 return; 1888 } 1889 1890 if (w.isVisible() && tempWindowStatesList.contains(parentWindow)) { 1891 tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w); 1892 } 1893 }, false /* traverseTopToBottom */); 1894 for (int i = 0; i < tempWindowStatesList.size(); i++) { 1895 outWindows.put(i, tempWindowStatesList.get(i)); 1896 } 1897 } 1898 findRootDisplayParentWindow(WindowState win)1899 private WindowState findRootDisplayParentWindow(WindowState win) { 1900 WindowState displayParentWindow = win.getDisplayContent().getParentWindow(); 1901 if (displayParentWindow == null) { 1902 return null; 1903 } 1904 WindowState candidate = displayParentWindow; 1905 while (candidate != null) { 1906 displayParentWindow = candidate; 1907 candidate = displayParentWindow.getDisplayContent().getParentWindow(); 1908 } 1909 return displayParentWindow; 1910 } 1911 getTopFocusWindow()1912 private WindowState getTopFocusWindow() { 1913 return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus; 1914 } 1915 1916 @Override toString()1917 public String toString() { 1918 return "WindowsForAccessibilityObserver{" 1919 + "mDisplayId=" + mDisplayId 1920 + ", mEmbeddedDisplayIdList=" 1921 + Arrays.toString(mEmbeddedDisplayIdList.toArray()) 1922 + ", mInitialized=" + mInitialized 1923 + '}'; 1924 } 1925 1926 private class MyHandler extends Handler { 1927 public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1; 1928 MyHandler(Looper looper)1929 public MyHandler(Looper looper) { 1930 super(looper, null, false); 1931 } 1932 1933 @Override 1934 @SuppressWarnings("unchecked") handleMessage(Message message)1935 public void handleMessage(Message message) { 1936 switch (message.what) { 1937 case MESSAGE_COMPUTE_CHANGED_WINDOWS: { 1938 computeChangedWindows(false); 1939 } break; 1940 } 1941 } 1942 } 1943 } 1944 1945 private static final class AccessibilityControllerInternalImpl 1946 implements AccessibilityControllerInternal { 1947 1948 private static AccessibilityControllerInternal sInstance; getInstance(WindowManagerService service)1949 static AccessibilityControllerInternal getInstance(WindowManagerService service) { 1950 synchronized (STATIC_LOCK) { 1951 if (sInstance == null) { 1952 sInstance = new AccessibilityControllerInternalImpl(service); 1953 } 1954 return sInstance; 1955 } 1956 } 1957 1958 private final AccessibilityTracing mTracing; AccessibilityControllerInternalImpl(WindowManagerService service)1959 private AccessibilityControllerInternalImpl(WindowManagerService service) { 1960 mTracing = AccessibilityTracing.getInstance(service); 1961 } 1962 1963 @Override startTrace()1964 public void startTrace() { 1965 mTracing.startTrace(); 1966 } 1967 1968 @Override stopTrace()1969 public void stopTrace() { 1970 mTracing.stopTrace(); 1971 } 1972 1973 @Override isAccessibilityTracingEnabled()1974 public boolean isAccessibilityTracingEnabled() { 1975 return mTracing.isEnabled(); 1976 } 1977 1978 @Override logTrace( String where, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace)1979 public void logTrace( 1980 String where, String callingParams, byte[] a11yDump, int callingUid, 1981 StackTraceElement[] stackTrace) { 1982 mTracing.logState(where, callingParams, a11yDump, callingUid, stackTrace); 1983 } 1984 1985 @Override logTrace( String where, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp, int processId, long threadId)1986 public void logTrace( 1987 String where, String callingParams, byte[] a11yDump, int callingUid, 1988 StackTraceElement[] callStack, long timeStamp, int processId, long threadId) { 1989 mTracing.logState(where, callingParams, a11yDump, callingUid, callStack, timeStamp, 1990 processId, threadId); 1991 } 1992 } 1993 1994 private static final class AccessibilityTracing { 1995 private static AccessibilityTracing sInstance; getInstance(WindowManagerService service)1996 static AccessibilityTracing getInstance(WindowManagerService service) { 1997 synchronized (STATIC_LOCK) { 1998 if (sInstance == null) { 1999 sInstance = new AccessibilityTracing(service); 2000 } 2001 return sInstance; 2002 } 2003 } 2004 2005 private static final int BUFFER_CAPACITY = 1024 * 1024 * 12; 2006 private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace.pb"; 2007 private static final String TRACE_DIRECTORY = "/data/misc/a11ytrace/"; 2008 private static final String TAG = "AccessibilityTracing"; 2009 private static final long MAGIC_NUMBER_VALUE = 2010 ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; 2011 2012 private final Object mLock = new Object(); 2013 private final WindowManagerService mService; 2014 private final File mTraceFile; 2015 private final TraceBuffer mBuffer; 2016 private final LogHandler mHandler; 2017 private volatile boolean mEnabled; 2018 AccessibilityTracing(WindowManagerService service)2019 AccessibilityTracing(WindowManagerService service) { 2020 mService = service; 2021 mTraceFile = new File(TRACE_FILENAME); 2022 mBuffer = new TraceBuffer(BUFFER_CAPACITY); 2023 HandlerThread workThread = new HandlerThread(TAG); 2024 workThread.start(); 2025 mHandler = new LogHandler(workThread.getLooper()); 2026 } 2027 2028 /** 2029 * Start the trace. 2030 */ startTrace()2031 void startTrace() { 2032 if (IS_USER) { 2033 Slog.e(TAG, "Error: Tracing is not supported on user builds."); 2034 return; 2035 } 2036 synchronized (mLock) { 2037 try { 2038 Files.createDirectories(Paths.get(TRACE_DIRECTORY)); 2039 mTraceFile.createNewFile(); 2040 } catch (Exception e) { 2041 Slog.e(TAG, "Error: Failed to create trace file."); 2042 return; 2043 } 2044 mEnabled = true; 2045 mBuffer.resetBuffer(); 2046 } 2047 } 2048 2049 /** 2050 * Stops the trace and write the current buffer to disk 2051 */ stopTrace()2052 void stopTrace() { 2053 if (IS_USER) { 2054 Slog.e(TAG, "Error: Tracing is not supported on user builds."); 2055 return; 2056 } 2057 synchronized (mLock) { 2058 mEnabled = false; 2059 if (mEnabled) { 2060 Slog.e(TAG, "Error: tracing enabled while waiting for flush."); 2061 return; 2062 } 2063 writeTraceToFile(); 2064 } 2065 } 2066 isEnabled()2067 boolean isEnabled() { 2068 return mEnabled; 2069 } 2070 2071 /** 2072 * Write an accessibility trace log entry. 2073 */ logState(String where)2074 void logState(String where) { 2075 if (!mEnabled) { 2076 return; 2077 } 2078 logState(where, ""); 2079 } 2080 2081 /** 2082 * Write an accessibility trace log entry. 2083 */ logState(String where, String callingParams)2084 void logState(String where, String callingParams) { 2085 if (!mEnabled) { 2086 return; 2087 } 2088 logState(where, callingParams, "".getBytes()); 2089 } 2090 2091 /** 2092 * Write an accessibility trace log entry. 2093 */ logState(String where, String callingParams, byte[] a11yDump)2094 void logState(String where, String callingParams, byte[] a11yDump) { 2095 if (!mEnabled) { 2096 return; 2097 } 2098 logState(where, callingParams, a11yDump, Binder.getCallingUid()); 2099 } 2100 2101 /** 2102 * Write an accessibility trace log entry. 2103 */ logState( String where, String callingParams, byte[] a11yDump, int callingUid)2104 void logState( 2105 String where, String callingParams, byte[] a11yDump, int callingUid) { 2106 if (!mEnabled) { 2107 return; 2108 } 2109 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 2110 2111 logState(where, callingParams, a11yDump, callingUid, stackTraceElements); 2112 } 2113 2114 /** 2115 * Write an accessibility trace log entry. 2116 */ logState(String where, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace)2117 void logState(String where, String callingParams, byte[] a11yDump, int callingUid, 2118 StackTraceElement[] stackTrace) { 2119 if (!mEnabled) { 2120 return; 2121 } 2122 2123 log(where, callingParams, a11yDump, callingUid, stackTrace, 2124 SystemClock.elapsedRealtimeNanos(), 2125 Process.myPid() + ":" + Application.getProcessName(), 2126 Thread.currentThread().getId() + ":" + Thread.currentThread().getName()); 2127 } 2128 2129 /** 2130 * Write an accessibility trace log entry. 2131 */ logState(String where, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId, long threadId)2132 void logState(String where, String callingParams, byte[] a11yDump, int callingUid, 2133 StackTraceElement[] callingStack, long timeStamp, int processId, long threadId) { 2134 if (!mEnabled) { 2135 return; 2136 } 2137 log(where, callingParams, a11yDump, callingUid, callingStack, timeStamp, 2138 String.valueOf(processId), String.valueOf(threadId)); 2139 } 2140 toStackTraceString(StackTraceElement[] stackTraceElements)2141 private String toStackTraceString(StackTraceElement[] stackTraceElements) { 2142 if (stackTraceElements == null) { 2143 return ""; 2144 } 2145 StringBuilder stringBuilder = new StringBuilder(); 2146 boolean skip = true; 2147 for (int i = 0; i < stackTraceElements.length; i++) { 2148 if (stackTraceElements[i].toString().contains( 2149 AccessibilityTracing.class.getSimpleName())) { 2150 skip = false; 2151 } else if (!skip) { 2152 stringBuilder.append(stackTraceElements[i].toString()).append("\n"); 2153 } 2154 } 2155 return stringBuilder.toString(); 2156 } 2157 2158 /** 2159 * Write the current state to the buffer 2160 */ log(String where, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, String processName, String threadName)2161 private void log(String where, String callingParams, byte[] a11yDump, int callingUid, 2162 StackTraceElement[] callingStack, long timeStamp, String processName, 2163 String threadName) { 2164 SomeArgs args = SomeArgs.obtain(); 2165 args.arg1 = timeStamp; 2166 args.arg2 = where; 2167 args.arg3 = processName; 2168 args.arg4 = threadName; 2169 args.arg5 = callingUid; 2170 args.arg6 = callingParams; 2171 args.arg7 = callingStack; 2172 args.arg8 = a11yDump; 2173 mHandler.obtainMessage(LogHandler.MESSAGE_LOG_TRACE_ENTRY, args).sendToTarget(); 2174 } 2175 2176 /** 2177 * Writes the trace buffer to new file for the bugreport. 2178 */ writeTraceToFile()2179 void writeTraceToFile() { 2180 mHandler.sendEmptyMessage(LogHandler.MESSAGE_WRITE_FILE); 2181 } 2182 2183 private class LogHandler extends Handler { 2184 public static final int MESSAGE_LOG_TRACE_ENTRY = 1; 2185 public static final int MESSAGE_WRITE_FILE = 2; 2186 LogHandler(Looper looper)2187 LogHandler(Looper looper) { 2188 super(looper); 2189 } 2190 2191 @Override handleMessage(Message message)2192 public void handleMessage(Message message) { 2193 switch (message.what) { 2194 case MESSAGE_LOG_TRACE_ENTRY: { 2195 final SomeArgs args = (SomeArgs) message.obj; 2196 try { 2197 ProtoOutputStream os = new ProtoOutputStream(); 2198 PackageManagerInternal pmInternal = 2199 LocalServices.getService(PackageManagerInternal.class); 2200 2201 long tokenOuter = os.start(ENTRY); 2202 String callingStack = 2203 toStackTraceString((StackTraceElement[]) args.arg7); 2204 2205 long reportedTimeStampNanos = (long) args.arg1; 2206 long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); 2207 long timeDiffNanos = 2208 currentElapsedRealtimeNanos - reportedTimeStampNanos; 2209 long currentTimeMillis = (new Date()).getTime(); 2210 long reportedTimeMillis = 2211 currentTimeMillis - (long) (timeDiffNanos / 1000000); 2212 SimpleDateFormat fm = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); 2213 2214 os.write(ELAPSED_REALTIME_NANOS, reportedTimeStampNanos); 2215 os.write(CALENDAR_TIME, fm.format(reportedTimeMillis).toString()); 2216 os.write(WHERE, (String) args.arg2); 2217 os.write(PROCESS_NAME, (String) args.arg3); 2218 os.write(THREAD_ID_NAME, (String) args.arg4); 2219 os.write(CALLING_PKG, pmInternal.getNameForUid((int) args.arg5)); 2220 os.write(CALLING_PARAMS, (String) args.arg6); 2221 os.write(CALLING_STACKS, callingStack); 2222 os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg8); 2223 2224 long tokenInner = os.start(WINDOW_MANAGER_SERVICE); 2225 synchronized (mService.mGlobalLock) { 2226 mService.dumpDebugLocked(os, WindowTraceLogLevel.ALL); 2227 } 2228 os.end(tokenInner); 2229 2230 os.end(tokenOuter); 2231 synchronized (mLock) { 2232 mBuffer.add(os); 2233 } 2234 } catch (Exception e) { 2235 Slog.e(TAG, "Exception while tracing state", e); 2236 } 2237 break; 2238 } 2239 case MESSAGE_WRITE_FILE: { 2240 synchronized (mLock) { 2241 writeTraceToFileInternal(); 2242 } 2243 break; 2244 } 2245 } 2246 } 2247 } 2248 2249 /** 2250 * Writes the trace buffer to disk. 2251 */ writeTraceToFileInternal()2252 private void writeTraceToFileInternal() { 2253 try { 2254 ProtoOutputStream proto = new ProtoOutputStream(); 2255 proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); 2256 mBuffer.writeTraceToFile(mTraceFile, proto); 2257 } catch (IOException e) { 2258 Slog.e(TAG, "Unable to write buffer to file", e); 2259 } 2260 } 2261 } 2262 } 2263