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