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