1 /*
2  * Copyright (C) 2016 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 android.server.am;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
22 import static android.server.am.ProtoExtractors.extract;
23 import static android.server.am.StateLogger.log;
24 import static android.server.am.StateLogger.logE;
25 import static android.view.Display.DEFAULT_DISPLAY;
26 
27 import static org.junit.Assert.fail;
28 
29 import android.content.res.Configuration;
30 import android.graphics.Rect;
31 import android.os.ParcelFileDescriptor;
32 import android.os.SystemClock;
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 import android.support.test.InstrumentationRegistry;
36 import android.view.nano.DisplayInfoProto;
37 
38 import com.android.server.wm.nano.AppTransitionProto;
39 import com.android.server.wm.nano.AppWindowTokenProto;
40 import com.android.server.wm.nano.ConfigurationContainerProto;
41 import com.android.server.wm.nano.DisplayFramesProto;
42 import com.android.server.wm.nano.DisplayProto;
43 import com.android.server.wm.nano.IdentifierProto;
44 import com.android.server.wm.nano.PinnedStackControllerProto;
45 import com.android.server.wm.nano.StackProto;
46 import com.android.server.wm.nano.TaskProto;
47 import com.android.server.wm.nano.WindowContainerProto;
48 import com.android.server.wm.nano.WindowManagerServiceDumpProto;
49 import com.android.server.wm.nano.WindowStateAnimatorProto;
50 import com.android.server.wm.nano.WindowStateProto;
51 import com.android.server.wm.nano.WindowSurfaceControllerProto;
52 import com.android.server.wm.nano.WindowTokenProto;
53 
54 import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
55 
56 import java.io.ByteArrayOutputStream;
57 import java.io.FileInputStream;
58 import java.io.IOException;
59 import java.nio.charset.StandardCharsets;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.HashMap;
63 import java.util.LinkedList;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.function.Predicate;
67 import java.util.stream.Collectors;
68 import java.util.stream.Stream;
69 
70 public class WindowManagerState {
71     public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
72     public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE";
73     public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN";
74     public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE";
75 
76     public static final String TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN";
77     public static final String TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE";
78     public static final String TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN";
79     public static final String TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE";
80 
81     public static final String TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY";
82     public static final String TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
83             "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
84     public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE";
85     public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE";
86     public static final String TRANSIT_TRANSLUCENT_ACTIVITY_OPEN =
87             "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
88     public static final String TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE =
89             "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
90 
91     public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
92 
93     private static final String DUMPSYS_WINDOW = "dumpsys window -a --proto";
94 
95     private static final String STARTING_WINDOW_PREFIX = "Starting ";
96     private static final String DEBUGGER_WINDOW_PREFIX = "Waiting For Debugger: ";
97 
98     // Windows in z-order with the top most at the front of the list.
99     private List<WindowState> mWindowStates = new ArrayList();
100     // Stacks in z-order with the top most at the front of the list, starting with primary display.
101     private final List<WindowStack> mStacks = new ArrayList();
102     // Stacks on all attached displays, in z-order with the top most at the front of the list.
103     private final Map<Integer, List<WindowStack>> mDisplayStacks
104             = new HashMap<>();
105     private List<Display> mDisplays = new ArrayList();
106     private String mFocusedWindow = null;
107     private String mFocusedApp = null;
108     private String mLastTransition = null;
109     private String mAppTransitionState = null;
110     private String mInputMethodWindowAppToken = null;
111     private Rect mDefaultPinnedStackBounds = new Rect();
112     private Rect mPinnedStackMovementBounds = new Rect();
113     private final LinkedList<String> mSysDump = new LinkedList();
114     private int mRotation;
115     private int mLastOrientation;
116     private boolean mDisplayFrozen;
117     private boolean mIsDockedStackMinimized;
118 
computeState()119     public void computeState() {
120         // It is possible the system is in the middle of transition to the right state when we get
121         // the dump. We try a few times to get the information we need before giving up.
122         int retriesLeft = 3;
123         boolean retry = false;
124         byte[] dump = null;
125 
126         log("==============================");
127         log("      WindowManagerState      ");
128         log("==============================");
129         do {
130             if (retry) {
131                 log("***Incomplete WM state. Retrying...");
132                 // Wait half a second between retries for window manager to finish transitioning...
133                 SystemClock.sleep(500);
134             }
135 
136             dump = executeShellCommand(DUMPSYS_WINDOW);
137             try {
138                 parseSysDumpProto(dump);
139             } catch (InvalidProtocolBufferNanoException ex) {
140                 throw new RuntimeException("Failed to parse dumpsys:\n"
141                         + new String(dump, StandardCharsets.UTF_8), ex);
142             }
143 
144             retry = mWindowStates.isEmpty() || mFocusedApp == null;
145         } while (retry && retriesLeft-- > 0);
146 
147         if (mWindowStates.isEmpty()) {
148             logE("No Windows found...");
149         }
150         if (mFocusedWindow == null) {
151             logE("No Focused Window...");
152         }
153         if (mFocusedApp == null) {
154             logE("No Focused App...");
155         }
156     }
157 
executeShellCommand(String cmd)158     private byte[] executeShellCommand(String cmd) {
159         try {
160             ParcelFileDescriptor pfd =
161                     InstrumentationRegistry.getInstrumentation().getUiAutomation()
162                             .executeShellCommand(cmd);
163             byte[] buf = new byte[512];
164             int bytesRead;
165             FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
166             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
167             while ((bytesRead = fis.read(buf)) != -1) {
168                 stdout.write(buf, 0, bytesRead);
169             }
170             fis.close();
171             return stdout.toByteArray();
172         } catch (IOException e) {
173             throw new RuntimeException(e);
174         }
175     }
176 
177 
parseSysDumpProto(byte[] sysDump)178     private void parseSysDumpProto(byte[] sysDump) throws InvalidProtocolBufferNanoException {
179         reset();
180         WindowManagerServiceDumpProto state = WindowManagerServiceDumpProto.parseFrom(sysDump);
181         List<WindowState> allWindows = new ArrayList<>();
182         Map<String, WindowState> windowMap = new HashMap<>();
183         if (state.focusedWindow != null) {
184             mFocusedWindow = state.focusedWindow.title;
185         }
186         mFocusedApp = state.focusedApp;
187         for (int i = 0; i < state.rootWindowContainer.displays.length; i++) {
188             DisplayProto displayProto = state.rootWindowContainer.displays[i];
189             final Display display = new Display(displayProto);
190             mDisplays.add(display);
191             allWindows.addAll(display.getWindows());
192             List<WindowStack> stacks = new ArrayList<>();
193             for (int j = 0; j < displayProto.stacks.length; j++) {
194                 StackProto stackProto = displayProto.stacks[j];
195                 final WindowStack stack = new WindowStack(stackProto);
196                 mStacks.add(stack);
197                 stacks.add(stack);
198                 allWindows.addAll(stack.getWindows());
199             }
200             mDisplayStacks.put(display.mDisplayId, stacks);
201 
202             // use properties from the default display only
203             if (display.getDisplayId() == DEFAULT_DISPLAY) {
204                 if (displayProto.dockedStackDividerController != null) {
205                     mIsDockedStackMinimized =
206                             displayProto.dockedStackDividerController.minimizedDock;
207                 }
208                 PinnedStackControllerProto pinnedStackProto = displayProto.pinnedStackController;
209                 if (pinnedStackProto != null) {
210                     mDefaultPinnedStackBounds = extract(pinnedStackProto.defaultBounds);
211                     mPinnedStackMovementBounds = extract(pinnedStackProto.movementBounds);
212                 }
213             }
214         }
215         for (WindowState w : allWindows) {
216             windowMap.put(w.getToken(), w);
217         }
218         for (int i = 0; i < state.rootWindowContainer.windows.length; i++) {
219             IdentifierProto identifierProto = state.rootWindowContainer.windows[i];
220             String hash_code = Integer.toHexString(identifierProto.hashCode);
221             mWindowStates.add(windowMap.get(hash_code));
222         }
223         if (state.inputMethodWindow != null) {
224             mInputMethodWindowAppToken = Integer.toHexString(state.inputMethodWindow.hashCode);
225         }
226         mDisplayFrozen = state.displayFrozen;
227         mRotation = state.rotation;
228         mLastOrientation = state.lastOrientation;
229         AppTransitionProto appTransitionProto = state.appTransition;
230         int appState = 0;
231         int lastTransition = 0;
232         if (appTransitionProto != null) {
233             appState = appTransitionProto.appTransitionState;
234             lastTransition = appTransitionProto.lastUsedAppTransition;
235         }
236         mAppTransitionState = appStateToString(appState);
237         mLastTransition = appTransitionToString(lastTransition);
238     }
239 
appStateToString(int appState)240     static String appStateToString(int appState) {
241         switch (appState) {
242             case AppTransitionProto.APP_STATE_IDLE:
243                 return "APP_STATE_IDLE";
244             case AppTransitionProto.APP_STATE_READY:
245                 return "APP_STATE_READY";
246             case AppTransitionProto.APP_STATE_RUNNING:
247                 return "APP_STATE_RUNNING";
248             case AppTransitionProto.APP_STATE_TIMEOUT:
249                 return "APP_STATE_TIMEOUT";
250             default:
251                 fail("Invalid AppTransitionState");
252                 return null;
253         }
254     }
255 
appTransitionToString(int transition)256     static String appTransitionToString(int transition) {
257         switch (transition) {
258             case AppTransitionProto.TRANSIT_UNSET: {
259                 return "TRANSIT_UNSET";
260             }
261             case AppTransitionProto.TRANSIT_NONE: {
262                 return "TRANSIT_NONE";
263             }
264             case AppTransitionProto.TRANSIT_ACTIVITY_OPEN: {
265                 return TRANSIT_ACTIVITY_OPEN;
266             }
267             case AppTransitionProto.TRANSIT_ACTIVITY_CLOSE: {
268                 return TRANSIT_ACTIVITY_CLOSE;
269             }
270             case AppTransitionProto.TRANSIT_TASK_OPEN: {
271                 return TRANSIT_TASK_OPEN;
272             }
273             case AppTransitionProto.TRANSIT_TASK_CLOSE: {
274                 return TRANSIT_TASK_CLOSE;
275             }
276             case AppTransitionProto.TRANSIT_TASK_TO_FRONT: {
277                 return "TRANSIT_TASK_TO_FRONT";
278             }
279             case AppTransitionProto.TRANSIT_TASK_TO_BACK: {
280                 return "TRANSIT_TASK_TO_BACK";
281             }
282             case AppTransitionProto.TRANSIT_WALLPAPER_CLOSE: {
283                 return TRANSIT_WALLPAPER_CLOSE;
284             }
285             case AppTransitionProto.TRANSIT_WALLPAPER_OPEN: {
286                 return TRANSIT_WALLPAPER_OPEN;
287             }
288             case AppTransitionProto.TRANSIT_WALLPAPER_INTRA_OPEN: {
289                 return TRANSIT_WALLPAPER_INTRA_OPEN;
290             }
291             case AppTransitionProto.TRANSIT_WALLPAPER_INTRA_CLOSE: {
292                 return TRANSIT_WALLPAPER_INTRA_CLOSE;
293             }
294             case AppTransitionProto.TRANSIT_TASK_OPEN_BEHIND: {
295                 return "TRANSIT_TASK_OPEN_BEHIND";
296             }
297             case AppTransitionProto.TRANSIT_ACTIVITY_RELAUNCH: {
298                 return "TRANSIT_ACTIVITY_RELAUNCH";
299             }
300             case AppTransitionProto.TRANSIT_DOCK_TASK_FROM_RECENTS: {
301                 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
302             }
303             case AppTransitionProto.TRANSIT_KEYGUARD_GOING_AWAY: {
304                 return TRANSIT_KEYGUARD_GOING_AWAY;
305             }
306             case AppTransitionProto.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
307                 return TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
308             }
309             case AppTransitionProto.TRANSIT_KEYGUARD_OCCLUDE: {
310                 return TRANSIT_KEYGUARD_OCCLUDE;
311             }
312             case AppTransitionProto.TRANSIT_KEYGUARD_UNOCCLUDE: {
313                 return TRANSIT_KEYGUARD_UNOCCLUDE;
314             }
315             case AppTransitionProto.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
316                 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
317             }
318             case AppTransitionProto.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
319                 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
320             }
321             default: {
322                 fail("Invalid lastUsedAppTransition");
323                 return null;
324             }
325         }
326     }
327 
getMatchingWindowTokens(final String windowName)328     List<String> getMatchingWindowTokens(final String windowName) {
329         return getMatchingWindows(ws -> windowName.equals(ws.getName()))
330                 .map(WindowState::getToken)
331                 .collect(Collectors.toList());
332     }
333 
getMatchingVisibleWindowState(final String windowName)334     public List<WindowState> getMatchingVisibleWindowState(final String windowName) {
335         return getMatchingWindows(ws -> ws.isShown() && windowName.equals(ws.getName()))
336                 .collect(Collectors.toList());
337     }
338 
getExitingWindows()339     List<WindowState> getExitingWindows() {
340         return getMatchingWindows(WindowState::isExitingWindow)
341                 .collect(Collectors.toList());
342     }
343 
getMatchingWindows(Predicate<WindowState> condition)344     private Stream<WindowState> getMatchingWindows(Predicate<WindowState> condition) {
345         return mWindowStates.stream().filter(condition);
346     }
347 
348     @Nullable
getWindowByPackageName(String packageName, int windowType)349     public WindowState getWindowByPackageName(String packageName, int windowType) {
350         final List<WindowState> windowList = getWindowsByPackageName(packageName, windowType);
351         return windowList.isEmpty() ? null : windowList.get(0);
352     }
353 
getWindowsByPackageName(String packageName, int... restrictToTypes)354     public List<WindowState> getWindowsByPackageName(String packageName, int... restrictToTypes) {
355         return getMatchingWindows(ws ->
356                 (ws.getName().equals(packageName) || ws.getName().startsWith(packageName + "/"))
357                 && Arrays.stream(restrictToTypes).anyMatch(type -> type == ws.getType()))
358                 .collect(Collectors.toList());
359     }
360 
getWindowStateForAppToken(String appToken)361     WindowState getWindowStateForAppToken(String appToken) {
362         return getMatchingWindows(ws -> ws.getToken().equals(appToken))
363                 .findFirst()
364                 .orElse(null);
365     }
366 
getDisplay(int displayId)367     Display getDisplay(int displayId) {
368         for (Display display : mDisplays) {
369             if (displayId == display.getDisplayId()) {
370                 return display;
371             }
372         }
373         return null;
374     }
375 
getDisplays()376     List<Display> getDisplays() {
377         return mDisplays;
378     }
379 
getFrontWindow()380     String getFrontWindow() {
381         if (mWindowStates == null || mWindowStates.isEmpty()) {
382             return null;
383         }
384         return mWindowStates.get(0).getName();
385     }
386 
getFocusedWindow()387     public String getFocusedWindow() {
388         return mFocusedWindow;
389     }
390 
getFocusedApp()391     public String getFocusedApp() {
392         return mFocusedApp;
393     }
394 
getLastTransition()395     String getLastTransition() {
396         return mLastTransition;
397     }
398 
getAppTransitionState()399     String getAppTransitionState() {
400         return mAppTransitionState;
401     }
402 
getFrontStackId(int displayId)403     int getFrontStackId(int displayId) {
404         return mDisplayStacks.get(displayId).get(0).mStackId;
405     }
406 
getFrontStackActivityType(int displayId)407     int getFrontStackActivityType(int displayId) {
408         return mDisplayStacks.get(displayId).get(0).getActivityType();
409     }
410 
getRotation()411     public int getRotation() {
412         return mRotation;
413     }
414 
getLastOrientation()415     int getLastOrientation() {
416         return mLastOrientation;
417     }
418 
containsStack(int stackId)419     boolean containsStack(int stackId) {
420         for (WindowStack stack : mStacks) {
421             if (stackId == stack.mStackId) {
422                 return true;
423             }
424         }
425         return false;
426     }
427 
containsStack(int windowingMode, int activityType)428     boolean containsStack(int windowingMode, int activityType) {
429         for (WindowStack stack : mStacks) {
430             if (activityType != ACTIVITY_TYPE_UNDEFINED
431                     && activityType != stack.getActivityType()) {
432                 continue;
433             }
434             if (windowingMode != WINDOWING_MODE_UNDEFINED
435                     && windowingMode != stack.getWindowingMode()) {
436                 continue;
437             }
438             return true;
439         }
440         return false;
441     }
442 
443     /**
444      * Check if there exists a window record with matching windowName.
445      */
containsWindow(String windowName)446     boolean containsWindow(String windowName) {
447         for (WindowState window : mWindowStates) {
448             if (window.getName().equals(windowName)) {
449                 return true;
450             }
451         }
452         return false;
453     }
454 
455     /**
456      * Check if at least one window which matches provided window name is visible.
457      */
isWindowVisible(String windowName)458     boolean isWindowVisible(String windowName) {
459         for (WindowState window : mWindowStates) {
460             if (window.getName().equals(windowName)) {
461                 if (window.isShown()) {
462                     return true;
463                 }
464             }
465         }
466         return false;
467     }
468 
allWindowsVisible(String windowName)469     boolean allWindowsVisible(String windowName) {
470         boolean allVisible = false;
471         for (WindowState window : mWindowStates) {
472             if (window.getName().equals(windowName)) {
473                 if (!window.isShown()) {
474                     log("[VISIBLE] not visible" + windowName);
475                     return false;
476                 }
477                 log("[VISIBLE] visible" + windowName);
478                 allVisible = true;
479             }
480         }
481         return allVisible;
482     }
483 
getStack(int stackId)484     WindowStack getStack(int stackId) {
485         for (WindowStack stack : mStacks) {
486             if (stackId == stack.mStackId) {
487                 return stack;
488             }
489         }
490         return null;
491     }
492 
getStandardStackByWindowingMode(int windowingMode)493     WindowStack getStandardStackByWindowingMode(int windowingMode) {
494         for (WindowStack stack : mStacks) {
495             if (stack.getActivityType() != ACTIVITY_TYPE_STANDARD) {
496                 continue;
497             }
498             if (stack.getWindowingMode() == windowingMode) {
499                 return stack;
500             }
501         }
502         return null;
503     }
504 
505     /** Get the stack position on its display. */
getStackIndexByActivityType(int activityType)506     int getStackIndexByActivityType(int activityType) {
507         for (Integer displayId : mDisplayStacks.keySet()) {
508             List<WindowStack> stacks = mDisplayStacks.get(displayId);
509             for (int i = 0; i < stacks.size(); i++) {
510                 if (activityType == stacks.get(i).getActivityType()) {
511                     return i;
512                 }
513             }
514         }
515         return -1;
516     }
517 
getInputMethodWindowState()518     WindowState getInputMethodWindowState() {
519         return getWindowStateForAppToken(mInputMethodWindowAppToken);
520     }
521 
getStableBounds()522     Rect getStableBounds() {
523         return getDisplay(DEFAULT_DISPLAY).mStableBounds;
524     }
525 
getDefaultPinnedStackBounds()526     Rect getDefaultPinnedStackBounds() {
527         return new Rect(mDefaultPinnedStackBounds);
528     }
529 
getPinnedStackMovementBounds()530     Rect getPinnedStackMovementBounds() {
531         return new Rect(mPinnedStackMovementBounds);
532     }
533 
findFirstWindowWithType(int type)534     WindowState findFirstWindowWithType(int type) {
535         for (WindowState window : mWindowStates) {
536             if (window.getType() == type) {
537                 return window;
538             }
539         }
540         return null;
541     }
542 
isDisplayFrozen()543     public boolean isDisplayFrozen() {
544         return mDisplayFrozen;
545     }
546 
isDockedStackMinimized()547     public boolean isDockedStackMinimized() {
548         return mIsDockedStackMinimized;
549     }
550 
getZOrder(WindowState w)551     public int getZOrder(WindowState w) {
552         return mWindowStates.size() - mWindowStates.indexOf(w);
553     }
554 
reset()555     private void reset() {
556         mSysDump.clear();
557         mStacks.clear();
558         mDisplays.clear();
559         mWindowStates.clear();
560         mDisplayStacks.clear();
561         mFocusedWindow = null;
562         mFocusedApp = null;
563         mLastTransition = null;
564         mInputMethodWindowAppToken = null;
565         mIsDockedStackMinimized = false;
566         mDefaultPinnedStackBounds.setEmpty();
567         mPinnedStackMovementBounds.setEmpty();
568         mRotation = 0;
569         mLastOrientation = 0;
570         mDisplayFrozen = false;
571     }
572 
573     static class WindowStack extends WindowContainer {
574 
575         int mStackId;
576         ArrayList<WindowTask> mTasks = new ArrayList<>();
577         boolean mWindowAnimationBackgroundSurfaceShowing;
578         boolean mAnimatingBounds;
579 
WindowStack(StackProto proto)580         WindowStack(StackProto proto) {
581             super(proto.windowContainer);
582             mStackId = proto.id;
583             mFullscreen = proto.fillsParent;
584             mBounds = extract(proto.bounds);
585             for (int i = 0; i < proto.tasks.length; i++) {
586                 TaskProto taskProto = proto.tasks[i];
587                 WindowTask task = new WindowTask(taskProto);
588                 mTasks.add(task);
589                 mSubWindows.addAll(task.getWindows());
590             }
591             mWindowAnimationBackgroundSurfaceShowing = proto.animationBackgroundSurfaceIsDimming;
592             mAnimatingBounds = proto.animatingBounds;
593         }
594 
getTask(int taskId)595         WindowTask getTask(int taskId) {
596             for (WindowTask task : mTasks) {
597                 if (taskId == task.mTaskId) {
598                     return task;
599                 }
600             }
601             return null;
602         }
603 
isWindowAnimationBackgroundSurfaceShowing()604         boolean isWindowAnimationBackgroundSurfaceShowing() {
605             return mWindowAnimationBackgroundSurfaceShowing;
606         }
607     }
608 
609     static class WindowTask extends WindowContainer {
610 
611         int mTaskId;
612         Rect mTempInsetBounds;
613         List<String> mAppTokens = new ArrayList<>();
614 
WindowTask(TaskProto proto)615         WindowTask(TaskProto proto) {
616             super(proto.windowContainer);
617             mTaskId = proto.id;
618             mFullscreen = proto.fillsParent;
619             mBounds = extract(proto.bounds);
620             for (int i = 0; i < proto.appWindowTokens.length; i++) {
621                 AppWindowTokenProto appWindowTokenProto = proto.appWindowTokens[i];
622                 mAppTokens.add(appWindowTokenProto.name);
623                 WindowTokenProto windowTokenProto = appWindowTokenProto.windowToken;
624                 for (int j = 0; j < windowTokenProto.windows.length; j++) {
625                     WindowStateProto windowProto = windowTokenProto.windows[j];
626                     WindowState window = new WindowState(windowProto);
627                     mSubWindows.add(window);
628                     mSubWindows.addAll(window.getWindows());
629                 }
630             }
631             mTempInsetBounds = extract(proto.tempInsetBounds);
632         }
633     }
634 
635     static class ConfigurationContainer {
636         final Configuration mOverrideConfiguration = new Configuration();
637         final Configuration mFullConfiguration = new Configuration();
638         final Configuration mMergedOverrideConfiguration = new Configuration();
639 
ConfigurationContainer(ConfigurationContainerProto proto)640         ConfigurationContainer(ConfigurationContainerProto proto) {
641             if (proto == null) {
642                 return;
643             }
644             mOverrideConfiguration.setTo(extract(proto.overrideConfiguration));
645             mFullConfiguration.setTo(extract(proto.fullConfiguration));
646             mMergedOverrideConfiguration.setTo(extract(proto.mergedOverrideConfiguration));
647         }
648 
getWindowingMode()649         int getWindowingMode() {
650             if (mFullConfiguration == null) {
651                 return WINDOWING_MODE_UNDEFINED;
652             }
653             return mFullConfiguration.windowConfiguration.getWindowingMode();
654         }
655 
getActivityType()656         int getActivityType() {
657             if (mFullConfiguration == null) {
658                 return ACTIVITY_TYPE_UNDEFINED;
659             }
660             return mFullConfiguration.windowConfiguration.getActivityType();
661         }
662     }
663 
664     static abstract class WindowContainer extends ConfigurationContainer {
665 
666         protected boolean mFullscreen;
667         protected Rect mBounds;
668         protected int mOrientation;
669         protected List<WindowState> mSubWindows = new ArrayList<>();
670 
WindowContainer(WindowContainerProto proto)671         WindowContainer(WindowContainerProto proto) {
672             super(proto.configurationContainer);
673             mOrientation = proto.orientation;
674         }
675 
getBounds()676         Rect getBounds() {
677             return mBounds;
678         }
679 
isFullscreen()680         boolean isFullscreen() {
681             return mFullscreen;
682         }
683 
getWindows()684         List<WindowState> getWindows() {
685             return mSubWindows;
686         }
687     }
688 
689     static class Display extends WindowContainer {
690 
691         private final int mDisplayId;
692         private Rect mDisplayRect = new Rect();
693         private Rect mAppRect = new Rect();
694         private int mDpi;
695         private Rect mStableBounds;
696         private String mName;
697 
Display(DisplayProto proto)698         public Display(DisplayProto proto) {
699             super(proto.windowContainer);
700             mDisplayId = proto.id;
701             for (int i = 0; i < proto.aboveAppWindows.length; i++) {
702                 addWindowsFromTokenProto(proto.aboveAppWindows[i]);
703             }
704             for (int i = 0; i < proto.belowAppWindows.length; i++) {
705                 addWindowsFromTokenProto(proto.belowAppWindows[i]);
706             }
707             for (int i = 0; i < proto.imeWindows.length; i++) {
708                 addWindowsFromTokenProto(proto.imeWindows[i]);
709             }
710             mDpi = proto.dpi;
711             DisplayInfoProto infoProto = proto.displayInfo;
712             if (infoProto != null) {
713                 mDisplayRect.set(0, 0, infoProto.logicalWidth, infoProto.logicalHeight);
714                 mAppRect.set(0, 0, infoProto.appWidth, infoProto.appHeight);
715                 mName = infoProto.name;
716             }
717             final DisplayFramesProto displayFramesProto = proto.displayFrames;
718             if (displayFramesProto != null) {
719                 mStableBounds = extract(displayFramesProto.stableBounds);
720             }
721         }
722 
addWindowsFromTokenProto(WindowTokenProto proto)723         private void addWindowsFromTokenProto(WindowTokenProto proto) {
724             for (int j = 0; j < proto.windows.length; j++) {
725                 WindowStateProto windowProto = proto.windows[j];
726                 WindowState childWindow = new WindowState(windowProto);
727                 mSubWindows.add(childWindow);
728                 mSubWindows.addAll(childWindow.getWindows());
729             }
730         }
731 
getDisplayId()732         int getDisplayId() {
733             return mDisplayId;
734         }
735 
getDpi()736         int getDpi() {
737             return mDpi;
738         }
739 
getDisplayRect()740         Rect getDisplayRect() {
741             return mDisplayRect;
742         }
743 
getAppRect()744         Rect getAppRect() {
745             return mAppRect;
746         }
747 
getName()748         String getName() {
749             return mName;
750         }
751 
752         @Override
toString()753         public String toString() {
754             return "Display #" + mDisplayId + ": name=" + mName + " mDisplayRect=" + mDisplayRect
755                     + " mAppRect=" + mAppRect;
756         }
757     }
758 
759     public static class WindowState extends WindowContainer {
760 
761         private static final int WINDOW_TYPE_NORMAL = 0;
762         private static final int WINDOW_TYPE_STARTING = 1;
763         private static final int WINDOW_TYPE_EXITING = 2;
764         private static final int WINDOW_TYPE_DEBUGGER = 3;
765 
766         private String mName;
767         private final String mAppToken;
768         private final int mWindowType;
769         private int mType = 0;
770         private int mDisplayId;
771         private int mStackId;
772         private int mLayer;
773         private boolean mShown;
774         private Rect mContainingFrame = new Rect();
775         private Rect mParentFrame = new Rect();
776         private Rect mContentFrame = new Rect();
777         private Rect mFrame = new Rect();
778         private Rect mSurfaceInsets = new Rect();
779         private Rect mContentInsets = new Rect();
780         private Rect mGivenContentInsets = new Rect();
781         private Rect mCrop = new Rect();
782 
WindowState(WindowStateProto proto)783         WindowState(WindowStateProto proto) {
784             super(proto.windowContainer);
785             IdentifierProto identifierProto = proto.identifier;
786             mName = identifierProto.title;
787             mAppToken = Integer.toHexString(identifierProto.hashCode);
788             mDisplayId = proto.displayId;
789             mStackId = proto.stackId;
790             if (proto.attributes != null) {
791                 mType = proto.attributes.type;
792             }
793             WindowStateAnimatorProto animatorProto = proto.animator;
794             if (animatorProto != null) {
795                 if (animatorProto.surface != null) {
796                     WindowSurfaceControllerProto surfaceProto = animatorProto.surface;
797                     mShown = surfaceProto.shown;
798                     mLayer = surfaceProto.layer;
799                 }
800                 mCrop = extract(animatorProto.lastClipRect);
801             }
802             mGivenContentInsets = extract(proto.givenContentInsets);
803             mFrame = extract(proto.frame);
804             mContainingFrame = extract(proto.containingFrame);
805             mParentFrame = extract(proto.parentFrame);
806             mContentFrame = extract(proto.contentFrame);
807             mContentInsets = extract(proto.contentInsets);
808             mSurfaceInsets = extract(proto.surfaceInsets);
809             if (mName.startsWith(STARTING_WINDOW_PREFIX)) {
810                 mWindowType = WINDOW_TYPE_STARTING;
811                 // Existing code depends on the prefix being removed
812                 mName = mName.substring(STARTING_WINDOW_PREFIX.length());
813             } else if (proto.animatingExit) {
814                 mWindowType = WINDOW_TYPE_EXITING;
815             } else if (mName.startsWith(DEBUGGER_WINDOW_PREFIX)) {
816                 mWindowType = WINDOW_TYPE_STARTING;
817                 mName = mName.substring(DEBUGGER_WINDOW_PREFIX.length());
818             } else {
819                 mWindowType = 0;
820             }
821             for (int i = 0; i < proto.childWindows.length; i++) {
822                 WindowStateProto childProto = proto.childWindows[i];
823                 WindowState childWindow = new WindowState(childProto);
824                 mSubWindows.add(childWindow);
825                 mSubWindows.addAll(childWindow.getWindows());
826             }
827         }
828 
829         @NonNull
getName()830         public String getName() {
831             return mName;
832         }
833 
getToken()834         String getToken() {
835             return mAppToken;
836         }
837 
isStartingWindow()838         boolean isStartingWindow() {
839             return mWindowType == WINDOW_TYPE_STARTING;
840         }
841 
isExitingWindow()842         boolean isExitingWindow() {
843             return mWindowType == WINDOW_TYPE_EXITING;
844         }
845 
isDebuggerWindow()846         boolean isDebuggerWindow() {
847             return mWindowType == WINDOW_TYPE_DEBUGGER;
848         }
849 
getDisplayId()850         int getDisplayId() {
851             return mDisplayId;
852         }
853 
getStackId()854         int getStackId() {
855             return mStackId;
856         }
857 
getContainingFrame()858         Rect getContainingFrame() {
859             return mContainingFrame;
860         }
861 
getFrame()862         public Rect getFrame() {
863             return mFrame;
864         }
865 
getSurfaceInsets()866         Rect getSurfaceInsets() {
867             return mSurfaceInsets;
868         }
869 
getContentInsets()870         Rect getContentInsets() {
871             return mContentInsets;
872         }
873 
getGivenContentInsets()874         Rect getGivenContentInsets() {
875             return mGivenContentInsets;
876         }
877 
getContentFrame()878         public Rect getContentFrame() {
879             return mContentFrame;
880         }
881 
getParentFrame()882         Rect getParentFrame() {
883             return mParentFrame;
884         }
885 
getCrop()886         Rect getCrop() {
887             return mCrop;
888         }
889 
isShown()890         public boolean isShown() {
891             return mShown;
892         }
893 
getType()894         public int getType() {
895             return mType;
896         }
897 
getWindowTypeSuffix(int windowType)898         private String getWindowTypeSuffix(int windowType) {
899             switch (windowType) {
900                 case WINDOW_TYPE_STARTING:
901                     return " STARTING";
902                 case WINDOW_TYPE_EXITING:
903                     return " EXITING";
904                 case WINDOW_TYPE_DEBUGGER:
905                     return " DEBUGGER";
906                 default:
907                     break;
908             }
909             return "";
910         }
911 
912         @Override
toString()913         public String toString() {
914             return "WindowState: {" + mAppToken + " " + mName
915                     + getWindowTypeSuffix(mWindowType) + "}" + " type=" + mType
916                     + " cf=" + mContainingFrame + " pf=" + mParentFrame;
917         }
918     }
919 }
920