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