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