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