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.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
25 import static android.server.wm.ComponentNameUtils.getActivityName;
26 import static android.server.wm.ProtoExtractors.extract;
27 import static android.server.wm.StateLogger.log;
28 import static android.server.wm.StateLogger.logE;
29 import static android.server.wm.TestTaskOrganizer.INVALID_TASK_ID;
30 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
31 import static android.view.Display.DEFAULT_DISPLAY;
32 
33 import static androidx.test.InstrumentationRegistry.getInstrumentation;
34 
35 import static com.google.common.truth.Truth.assertWithMessage;
36 
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assert.fail;
39 
40 import android.app.ActivityTaskManager;
41 import android.content.ComponentName;
42 import android.content.res.Configuration;
43 import android.graphics.Point;
44 import android.graphics.Rect;
45 import android.os.ParcelFileDescriptor;
46 import android.os.SystemClock;
47 import android.util.SparseArray;
48 import android.view.WindowManager;
49 import android.view.nano.DisplayInfoProto;
50 import android.view.nano.ViewProtoEnums;
51 
52 import androidx.annotation.NonNull;
53 import androidx.annotation.Nullable;
54 
55 import com.android.server.wm.nano.ActivityRecordProto;
56 import com.android.server.wm.nano.AppTransitionProto;
57 import com.android.server.wm.nano.ConfigurationContainerProto;
58 import com.android.server.wm.nano.DisplayAreaProto;
59 import com.android.server.wm.nano.DisplayContentProto;
60 import com.android.server.wm.nano.DisplayFramesProto;
61 import com.android.server.wm.nano.DisplayRotationProto;
62 import com.android.server.wm.nano.IdentifierProto;
63 import com.android.server.wm.nano.KeyguardControllerProto;
64 import com.android.server.wm.nano.PinnedTaskControllerProto;
65 import com.android.server.wm.nano.RootWindowContainerProto;
66 import com.android.server.wm.nano.TaskFragmentProto;
67 import com.android.server.wm.nano.TaskProto;
68 import com.android.server.wm.nano.WindowContainerChildProto;
69 import com.android.server.wm.nano.WindowContainerProto;
70 import com.android.server.wm.nano.WindowFramesProto;
71 import com.android.server.wm.nano.WindowManagerServiceDumpProto;
72 import com.android.server.wm.nano.WindowStateAnimatorProto;
73 import com.android.server.wm.nano.WindowStateProto;
74 import com.android.server.wm.nano.WindowSurfaceControllerProto;
75 import com.android.server.wm.nano.WindowTokenProto;
76 
77 import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
78 
79 import java.io.ByteArrayOutputStream;
80 import java.io.FileInputStream;
81 import java.io.IOException;
82 import java.nio.charset.StandardCharsets;
83 import java.util.ArrayList;
84 import java.util.Arrays;
85 import java.util.List;
86 import java.util.Objects;
87 import java.util.function.Consumer;
88 import java.util.function.Predicate;
89 import java.util.stream.Collectors;
90 import java.util.stream.Stream;
91 
92 public class WindowManagerState {
93 
94     public static final String STATE_INITIALIZING = "INITIALIZING";
95     public static final String STATE_STARTED = "STARTED";
96     public static final String STATE_RESUMED = "RESUMED";
97     public static final String STATE_PAUSED = "PAUSED";
98     public static final String STATE_STOPPED = "STOPPED";
99     public static final String STATE_DESTROYED = "DESTROYED";
100     public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
101     public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE";
102     public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN";
103     public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE";
104     public static final String TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN";
105     public static final String TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE";
106     public static final String TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN";
107     public static final String TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE";
108     public static final String TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY";
109     public static final String TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
110             "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
111     public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE";
112     public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE";
113     public static final String TRANSIT_TRANSLUCENT_ACTIVITY_OPEN =
114             "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
115     public static final String TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE =
116             "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
117     public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
118     public static final String APP_STATE_RUNNING = "APP_STATE_RUNNING";
119 
120     private static final String DUMPSYS_WINDOW = "dumpsys window -a --proto";
121     private static final String STARTING_WINDOW_PREFIX = "Starting ";
122     private static final String DEBUGGER_WINDOW_PREFIX = "Waiting For Debugger: ";
123     /** @see WindowManager.LayoutParams */
124     private static final int TYPE_NAVIGATION_BAR = 2019;
125     /** @see WindowManager.LayoutParams */
126     private static final int TYPE_NAVIGATION_BAR_PANEL = 2024;
127     /** @see WindowManager.LayoutParams */
128     private static final int TYPE_NOTIFICATION_SHADE = 2040;
129 
130     private RootWindowContainer mRoot = null;
131     // Displays in z-order with the top most at the front of the list, starting with primary.
132     private final List<DisplayContent> mDisplays = new ArrayList<>();
133     /**
134      * Root tasks in z-order with the top most at the front of the list, starting with primary
135      * display.
136      */
137     private final List<Task> mRootTasks = new ArrayList<>();
138     // Windows in z-order with the top most at the front of the list.
139     private final List<WindowState> mWindowStates = new ArrayList<>();
140     private KeyguardControllerState mKeyguardControllerState;
141     private final List<String> mPendingActivities = new ArrayList<>();
142     private int mTopFocusedTaskId = -1;
143     private int mFocusedDisplayId = DEFAULT_DISPLAY;
144     private String mFocusedWindow = null;
145     private String mFocusedApp = null;
146     private Boolean mIsHomeRecentsComponent;
147     private int mDefaultMinSizeOfResizableTaskDp;
148     private String mTopResumedActivityRecord = null;
149     final List<String> mResumedActivitiesInRootTasks = new ArrayList<>();
150     final List<String> mResumedActivitiesInDisplays = new ArrayList<>();
151     private Rect mDefaultPinnedStackBounds = new Rect();
152     private Rect mPinnedStackMovementBounds = new Rect();
153     private String mInputMethodWindowAppToken = null;
154     private boolean mDisplayFrozen;
155     private boolean mSanityCheckFocusedWindow = true;
156 
appStateToString(int appState)157     static String appStateToString(int appState) {
158         switch (appState) {
159             case AppTransitionProto.APP_STATE_IDLE:
160                 return "APP_STATE_IDLE";
161             case AppTransitionProto.APP_STATE_READY:
162                 return "APP_STATE_READY";
163             case AppTransitionProto.APP_STATE_RUNNING:
164                 return "APP_STATE_RUNNING";
165             case AppTransitionProto.APP_STATE_TIMEOUT:
166                 return "APP_STATE_TIMEOUT";
167             default:
168                 fail("Invalid AppTransitionState");
169                 return null;
170         }
171     }
172 
appTransitionToString(int transition)173     static String appTransitionToString(int transition) {
174         switch (transition) {
175             case ViewProtoEnums.TRANSIT_UNSET: {
176                 return "TRANSIT_UNSET";
177             }
178             case ViewProtoEnums.TRANSIT_NONE: {
179                 return "TRANSIT_NONE";
180             }
181             case ViewProtoEnums.TRANSIT_ACTIVITY_OPEN: {
182                 return TRANSIT_ACTIVITY_OPEN;
183             }
184             case ViewProtoEnums.TRANSIT_ACTIVITY_CLOSE: {
185                 return TRANSIT_ACTIVITY_CLOSE;
186             }
187             case ViewProtoEnums.TRANSIT_TASK_OPEN: {
188                 return TRANSIT_TASK_OPEN;
189             }
190             case ViewProtoEnums.TRANSIT_TASK_CLOSE: {
191                 return TRANSIT_TASK_CLOSE;
192             }
193             case ViewProtoEnums.TRANSIT_TASK_TO_FRONT: {
194                 return "TRANSIT_TASK_TO_FRONT";
195             }
196             case ViewProtoEnums.TRANSIT_TASK_TO_BACK: {
197                 return "TRANSIT_TASK_TO_BACK";
198             }
199             case ViewProtoEnums.TRANSIT_WALLPAPER_CLOSE: {
200                 return TRANSIT_WALLPAPER_CLOSE;
201             }
202             case ViewProtoEnums.TRANSIT_WALLPAPER_OPEN: {
203                 return TRANSIT_WALLPAPER_OPEN;
204             }
205             case ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_OPEN: {
206                 return TRANSIT_WALLPAPER_INTRA_OPEN;
207             }
208             case ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_CLOSE: {
209                 return TRANSIT_WALLPAPER_INTRA_CLOSE;
210             }
211             case ViewProtoEnums.TRANSIT_TASK_OPEN_BEHIND: {
212                 return "TRANSIT_TASK_OPEN_BEHIND";
213             }
214             case ViewProtoEnums.TRANSIT_ACTIVITY_RELAUNCH: {
215                 return "TRANSIT_ACTIVITY_RELAUNCH";
216             }
217             case ViewProtoEnums.TRANSIT_DOCK_TASK_FROM_RECENTS: {
218                 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
219             }
220             case ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY: {
221                 return TRANSIT_KEYGUARD_GOING_AWAY;
222             }
223             case ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
224                 return TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
225             }
226             case ViewProtoEnums.TRANSIT_KEYGUARD_OCCLUDE: {
227                 return TRANSIT_KEYGUARD_OCCLUDE;
228             }
229             case ViewProtoEnums.TRANSIT_KEYGUARD_UNOCCLUDE: {
230                 return TRANSIT_KEYGUARD_UNOCCLUDE;
231             }
232             case ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
233                 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
234             }
235             case ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
236                 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
237             }
238             case ViewProtoEnums.TRANSIT_CRASHING_ACTIVITY_CLOSE: {
239                 return "TRANSIT_CRASHING_ACTIVITY_CLOSE";
240             }
241             default: {
242                 fail("Invalid lastUsedAppTransition");
243                 return null;
244             }
245         }
246     }
247 
isValidNavBarType(WindowState navState)248     static boolean isValidNavBarType(WindowState navState) {
249         return TYPE_NAVIGATION_BAR == navState.getType();
250     }
251 
252     /**
253      * For a given WindowContainer, traverse down the hierarchy and add all children of type
254      * {@code T} to {@code outChildren}.
255      */
collectDescendantsOfType(Class<T> clazz, WindowContainer root, List<T> outChildren)256     private static <T extends WindowContainer> void collectDescendantsOfType(Class<T> clazz,
257             WindowContainer root, List<T> outChildren) {
258         collectDescendantsOfTypeIf(clazz, t -> true, root, outChildren);
259     }
260 
261     /**
262      * For a given WindowContainer, traverse down the hierarchy and add all children of type
263      * {@code T} to {@code outChildren} if the child passes the test {@code predicate}.
264      */
collectDescendantsOfTypeIf(Class<T> clazz, Predicate<T> predicate, WindowContainer root, List<T> outChildren)265     private static <T extends WindowContainer> void collectDescendantsOfTypeIf(Class<T> clazz,
266             Predicate<T> predicate, WindowContainer root, List<T> outChildren) {
267         // Traverse top to bottom
268         for (int i = root.mChildren.size()-1; i >= 0; i--) {
269             final WindowContainer child = root.mChildren.get(i);
270             if (clazz.isInstance(child)) {
271                 if(predicate.test(clazz.cast(child))) {
272                     outChildren.add(clazz.cast(child));
273                 }
274             }
275             collectDescendantsOfTypeIf(clazz, predicate, child, outChildren);
276         }
277     }
278 
279     /**
280      * For a given WindowContainer, traverse down the hierarchy and add all immediate children of
281      * type {@code T} to {@code outChildren}.
282      */
collectChildrenOfType(Class<T> clazz, WindowContainer root, List<T> outChildren)283     private static <T extends WindowContainer> void collectChildrenOfType(Class<T> clazz,
284             WindowContainer root, List<T> outChildren) {
285         for (int i = root.mChildren.size()-1; i >= 0; i--) {
286             final WindowContainer child = root.mChildren.get(i);
287             if (clazz.isInstance(child)) {
288                 outChildren.add(clazz.cast(child));
289             }
290         }
291     }
292 
293     /** Enable/disable the mFocusedWindow check during the computeState.*/
setSanityCheckWithFocusedWindow(boolean sanityCheckFocusedWindow)294     void setSanityCheckWithFocusedWindow(boolean sanityCheckFocusedWindow) {
295         mSanityCheckFocusedWindow = sanityCheckFocusedWindow;
296     }
297 
computeState()298     public void computeState() {
299         // It is possible the system is in the middle of transition to the right state when we get
300         // the dump. We try a few times to get the information we need before giving up.
301         int retriesLeft = 3;
302         boolean retry = false;
303         byte[] dump = null;
304 
305         log("==============================");
306         log("     WindowManagerState     ");
307         log("==============================");
308 
309         do {
310             if (retry) {
311                 log("***Incomplete AM state. Retrying...");
312                 // Wait half a second between retries for activity manager to finish transitioning.
313                 SystemClock.sleep(500);
314             }
315 
316             dump = executeShellCommand(DUMPSYS_WINDOW);
317             try {
318                 parseSysDumpProto(dump);
319             } catch (InvalidProtocolBufferNanoException ex) {
320                 throw new RuntimeException("Failed to parse dumpsys:\n"
321                         + new String(dump, StandardCharsets.UTF_8), ex);
322             }
323 
324             retry = mRootTasks.isEmpty() || mTopFocusedTaskId == -1 || mWindowStates.isEmpty()
325                     || mFocusedApp == null || (mSanityCheckFocusedWindow && mFocusedWindow == null)
326                     || (mTopResumedActivityRecord == null
327                     || mResumedActivitiesInRootTasks.isEmpty())
328                     && !mKeyguardControllerState.keyguardShowing;
329         } while (retry && retriesLeft-- > 0);
330 
331         if (mRootTasks.isEmpty()) {
332             logE("No root tasks found...");
333         }
334         if (mTopFocusedTaskId == -1) {
335             logE("No focused task found...");
336         }
337         if (mTopResumedActivityRecord == null) {
338             logE("No focused activity found...");
339         }
340         if (mResumedActivitiesInRootTasks.isEmpty()) {
341             logE("No resumed activities found...");
342         }
343         if (mWindowStates.isEmpty()) {
344             logE("No Windows found...");
345         }
346         if (mFocusedWindow == null) {
347             logE("No Focused Window...");
348         }
349         if (mFocusedApp == null) {
350             logE("No Focused App...");
351         }
352     }
353 
executeShellCommand(String cmd)354     private byte[] executeShellCommand(String cmd) {
355         try {
356             ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
357                     .executeShellCommand(cmd);
358             byte[] buf = new byte[512];
359             int bytesRead;
360             FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
361             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
362             while ((bytesRead = fis.read(buf)) != -1) {
363                 stdout.write(buf, 0, bytesRead);
364             }
365             fis.close();
366             return stdout.toByteArray();
367         } catch (IOException e) {
368             throw new RuntimeException(e);
369         }
370     }
371 
372     /** Update WindowManagerState state for a newly added DisplayContent. */
updateForDisplayContent(DisplayContent display)373     private void updateForDisplayContent(DisplayContent display) {
374         if (display.mResumedActivity != null) {
375             mResumedActivitiesInDisplays.add(display.mResumedActivity);
376         }
377 
378         for (int i = 0; i < display.mRootTasks.size(); i++) {
379             Task task = display.mRootTasks.get(i);
380             mRootTasks.add(task);
381             addResumedActivity(task);
382         }
383 
384         if (display.mDefaultPinnedStackBounds != null) {
385             mDefaultPinnedStackBounds = display.mDefaultPinnedStackBounds;
386             mPinnedStackMovementBounds = display.mPinnedStackMovementBounds;
387         }
388     }
389 
addResumedActivity(Task task)390     private void addResumedActivity(Task task) {
391         final int numChildTasks = task.mTasks.size();
392         if (numChildTasks > 0) {
393             for (int i = numChildTasks - 1; i >=0; i--) {
394                 addResumedActivity(task.mTasks.get(i));
395             }
396         } else if (task.mResumedActivity != null) {
397             mResumedActivitiesInRootTasks.add(task.mResumedActivity);
398         }
399     }
400 
parseSysDumpProto(byte[] sysDump)401     private void parseSysDumpProto(byte[] sysDump) throws InvalidProtocolBufferNanoException {
402         reset();
403 
404         WindowManagerServiceDumpProto state = WindowManagerServiceDumpProto.parseFrom(sysDump);
405         final RootWindowContainerProto root = state.rootWindowContainer;
406         if (state.focusedWindow != null) {
407             mFocusedWindow = state.focusedWindow.title;
408         }
409         mRoot = new RootWindowContainer(root);
410         collectDescendantsOfType(DisplayContent.class, mRoot, mDisplays);
411         for (int i = 0; i < mDisplays.size(); i++) {
412             DisplayContent display = mDisplays.get(i);
413             updateForDisplayContent(display);
414         }
415         mKeyguardControllerState = new KeyguardControllerState(root.keyguardController);
416         mFocusedApp = state.focusedApp;
417         mFocusedDisplayId = state.focusedDisplayId;
418         final DisplayContent focusedDisplay = getDisplay(mFocusedDisplayId);
419         if (focusedDisplay != null) {
420             mTopFocusedTaskId = focusedDisplay.mFocusedRootTaskId;
421             mTopResumedActivityRecord = focusedDisplay.mResumedActivity;
422         }
423         mIsHomeRecentsComponent = new Boolean(root.isHomeRecentsComponent);
424         mDefaultMinSizeOfResizableTaskDp = root.defaultMinSizeResizableTask;
425 
426         for (int i = 0; i < root.pendingActivities.length; i++) {
427             mPendingActivities.add(root.pendingActivities[i].title);
428         }
429 
430         collectDescendantsOfType(WindowState.class, mRoot, mWindowStates);
431 
432         if (state.inputMethodWindow != null) {
433             mInputMethodWindowAppToken = Integer.toHexString(state.inputMethodWindow.hashCode);
434         }
435         mDisplayFrozen = state.displayFrozen;
436     }
437 
reset()438     private void reset() {
439         mRoot = null;
440         mDisplays.clear();
441         mRootTasks.clear();
442         mWindowStates.clear();
443         mTopFocusedTaskId = -1;
444         mFocusedDisplayId = DEFAULT_DISPLAY;
445         mFocusedWindow = null;
446         mFocusedApp = null;
447         mTopResumedActivityRecord = null;
448         mResumedActivitiesInRootTasks.clear();
449         mResumedActivitiesInDisplays.clear();
450         mKeyguardControllerState = null;
451         mIsHomeRecentsComponent = null;
452         mPendingActivities.clear();
453         mDefaultPinnedStackBounds.setEmpty();
454         mPinnedStackMovementBounds.setEmpty();
455         mInputMethodWindowAppToken = null;
456         mDisplayFrozen = false;
457     }
458 
getFocusedApp()459     public String getFocusedApp() {
460         return mFocusedApp;
461     }
462 
getFocusedWindow()463     public String getFocusedWindow() {
464         return mFocusedWindow;
465     }
466 
467     /** @return Whether the home activity is the recents component. */
isHomeRecentsComponent()468     boolean isHomeRecentsComponent() {
469         if (mIsHomeRecentsComponent == null) {
470             computeState();
471         }
472         return mIsHomeRecentsComponent;
473     }
474 
getDisplay(int displayId)475     DisplayContent getDisplay(int displayId) {
476         for (DisplayContent display : mDisplays) {
477             if (display.mId == displayId) {
478                 return display;
479             }
480         }
481         return null;
482     }
483 
484     @Nullable
getTaskDisplayArea(ComponentName activityName)485     DisplayArea getTaskDisplayArea(ComponentName activityName) {
486         final List<DisplayArea> result = new ArrayList<>();
487         for (DisplayContent display : mDisplays) {
488             final DisplayArea tda = display.getTaskDisplayArea(activityName);
489             if (tda != null) {
490                 result.add(tda);
491             }
492         }
493         assertWithMessage("There must be exactly one activity among all TaskDisplayAreas.")
494                 .that(result.size()).isAtMost(1);
495 
496         return result.stream().findFirst().orElse(null);
497     }
498 
499     @Nullable
getDisplayArea(String windowName)500     DisplayArea getDisplayArea(String windowName) {
501         final List<DisplayArea> result = new ArrayList<>();
502         for (DisplayContent display : mDisplays) {
503             final DisplayArea da = display.getDisplayArea(windowName);
504             if (da != null) {
505                 result.add(da);
506             }
507         }
508         assertWithMessage("There must be exactly one window among all DisplayAreas.")
509                 .that(result.size()).isAtMost(1);
510 
511         return result.stream().findFirst().orElse(null);
512     }
513 
getFrontRootTaskId(int displayId)514     int getFrontRootTaskId(int displayId) {
515         return getDisplay(displayId).mRootTasks.get(0).mRootTaskId;
516     }
517 
getFrontRootTaskActivityType(int displayId)518     public int getFrontRootTaskActivityType(int displayId) {
519         return getDisplay(displayId).mRootTasks.get(0).getActivityType();
520     }
521 
getFrontRootTaskWindowingMode(int displayId)522     public int getFrontRootTaskWindowingMode(int displayId) {
523         return getDisplay(displayId).mRootTasks.get(0).getWindowingMode();
524     }
525 
getTopActivityName(int displayId)526     public String getTopActivityName(int displayId) {
527         if (!getDisplay(displayId).mRootTasks.isEmpty()) {
528             final Task topRootTask = getDisplay(displayId).mRootTasks.get(0);
529             final Task topTask = topRootTask.getTopTask();
530             if (!topTask.mActivities.isEmpty()) {
531                 return topTask.mActivities.get(0).name;
532             }
533         }
534         return null;
535     }
536 
getFocusedTaskId()537     int getFocusedTaskId() {
538         return mTopFocusedTaskId;
539     }
540 
getFocusedRootTaskActivityType()541     public int getFocusedRootTaskActivityType() {
542         final Task rootTask = getRootTask(mTopFocusedTaskId);
543         return rootTask != null ? rootTask.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
544     }
545 
getFocusedRootTaskWindowingMode()546     public int getFocusedRootTaskWindowingMode() {
547         final Task rootTask = getRootTask(mTopFocusedTaskId);
548         return rootTask != null ? rootTask.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
549     }
550 
getFocusedActivity()551     public String getFocusedActivity() {
552         return mTopResumedActivityRecord;
553     }
554 
getResumedActivitiesCount()555     public int getResumedActivitiesCount() {
556         return mResumedActivitiesInRootTasks.size();
557     }
558 
getResumedActivitiesCountInPackage(String packageName)559     public int getResumedActivitiesCountInPackage(String packageName) {
560         final String componentPrefix = packageName + "/";
561         int count = 0;
562         for (int i = mDisplays.size() - 1; i >= 0; --i) {
563             final ArrayList<Task> rootTasks = mDisplays.get(i).getRootTasks();
564             for (int j = rootTasks.size() - 1; j >= 0; --j) {
565                 final String resumedActivity = rootTasks.get(j).mResumedActivity;
566                 if (resumedActivity != null && resumedActivity.startsWith(componentPrefix)) {
567                     count++;
568                 }
569             }
570         }
571         return count;
572     }
573 
getResumedActivityOnDisplay(int displayId)574     public String getResumedActivityOnDisplay(int displayId) {
575         return getDisplay(displayId).mResumedActivity;
576     }
577 
getKeyguardControllerState()578     public KeyguardControllerState getKeyguardControllerState() {
579         return mKeyguardControllerState;
580     }
581 
containsRootTasks(int windowingMode, int activityType)582     public boolean containsRootTasks(int windowingMode, int activityType) {
583         return countRootTasks(windowingMode, activityType) > 0;
584     }
585 
countRootTasks(int windowingMode, int activityType)586     public int countRootTasks(int windowingMode, int activityType) {
587         int count = 0;
588         for (Task rootTask : mRootTasks) {
589             if (activityType != ACTIVITY_TYPE_UNDEFINED
590                     && activityType != rootTask.getActivityType()) {
591                 continue;
592             }
593             if (windowingMode != WINDOWING_MODE_UNDEFINED
594                     && windowingMode != rootTask.getWindowingMode()) {
595                 continue;
596             }
597             ++count;
598         }
599         return count;
600     }
601 
getRootTask(int taskId)602     public Task getRootTask(int taskId) {
603         for (Task rootTask : mRootTasks) {
604             if (taskId == rootTask.mRootTaskId) {
605                 return rootTask;
606             }
607         }
608         return null;
609     }
610 
getRootTaskByActivityType(int activityType)611     public Task getRootTaskByActivityType(int activityType) {
612         for (Task rootTask : mRootTasks) {
613             if (activityType == rootTask.getActivityType()) {
614                 return rootTask;
615             }
616         }
617         return null;
618     }
619 
getStandardTaskCountByWindowingMode(int windowingMode)620     public int getStandardTaskCountByWindowingMode(int windowingMode) {
621         int count = 0;
622         for (Task rootTask : mRootTasks) {
623             if (rootTask.getActivityType() != ACTIVITY_TYPE_STANDARD) {
624                 continue;
625             }
626             if (rootTask.getWindowingMode() == windowingMode) {
627                 count += rootTask.mTasks.isEmpty() ? 1 : rootTask.mTasks.size();
628             }
629         }
630         return count;
631     }
632 
633     /** Gets the position of root task on its display with the given {@code activityType}. */
getRootTaskIndexByActivityType(int activityType)634     int getRootTaskIndexByActivityType(int activityType) {
635         for (DisplayContent display : mDisplays) {
636             for (int i = 0; i < display.mRootTasks.size(); i++) {
637                 if (activityType == display.mRootTasks.get(i).getActivityType()) {
638                     return i;
639                 }
640             }
641         }
642         return -1;
643     }
644 
645     /** Gets the root task on its display with the given {@code activityName}. */
646     @Nullable
getRootTaskByActivity(ComponentName activityName)647     Task getRootTaskByActivity(ComponentName activityName) {
648         for (DisplayContent display : mDisplays) {
649             for (int i = display.mRootTasks.size() - 1; i >= 0; --i) {
650                 final Task rootTask = display.mRootTasks.get(i);
651                 if (rootTask.containsActivity(activityName)) return rootTask;
652             }
653         }
654         return null;
655     }
656 
657     /** Get display id by activity on it. */
getDisplayByActivity(ComponentName activityComponent)658     public int getDisplayByActivity(ComponentName activityComponent) {
659         final Task task = getTaskByActivity(activityComponent);
660         if (task == null) {
661             return -1;
662         }
663         return getRootTask(task.mRootTaskId).mDisplayId;
664     }
665 
getDisplays()666     List<DisplayContent> getDisplays() {
667         return new ArrayList<>(mDisplays);
668     }
669 
getRootTasks()670     public List<Task> getRootTasks() {
671         return new ArrayList<>(mRootTasks);
672     }
673 
getRootTaskCount()674     public int getRootTaskCount() {
675         return mRootTasks.size();
676     }
677 
getDisplayCount()678     public int getDisplayCount() {
679         return mDisplays.size();
680     }
681 
containsActivity(ComponentName activityName)682     public boolean containsActivity(ComponentName activityName) {
683         for (Task rootTask : mRootTasks) {
684             if (rootTask.containsActivity(activityName)) return true;
685         }
686         return false;
687     }
688 
containsNoneOf(Iterable<ComponentName> activityNames)689     public boolean containsNoneOf(Iterable<ComponentName> activityNames) {
690         for (ComponentName activityName : activityNames) {
691             for (Task rootTask : mRootTasks) {
692                 if (rootTask.containsActivity(activityName)) return false;
693             }
694         }
695         return true;
696     }
697 
containsActivityInWindowingMode(ComponentName activityName, int windowingMode)698     public boolean containsActivityInWindowingMode(ComponentName activityName, int windowingMode) {
699         for (Task rootTask : mRootTasks) {
700             final Activity activity = rootTask.getActivity(activityName);
701             if (activity != null && activity.getWindowingMode() == windowingMode) {
702                 return true;
703             }
704         }
705         return false;
706     }
707 
isActivityVisible(ComponentName activityName)708     public boolean isActivityVisible(ComponentName activityName) {
709         for (Task rootTask : mRootTasks) {
710             final Activity activity = rootTask.getActivity(activityName);
711             if (activity != null) return activity.visible;
712         }
713         return false;
714     }
715 
isActivityTranslucent(ComponentName activityName)716     public boolean isActivityTranslucent(ComponentName activityName) {
717         for (Task rootTask : mRootTasks) {
718             final Activity activity = rootTask.getActivity(activityName);
719             if (activity != null) return activity.translucent;
720         }
721         return false;
722     }
723 
isBehindOpaqueActivities(ComponentName activityName)724     public boolean isBehindOpaqueActivities(ComponentName activityName) {
725         final String fullName = getActivityName(activityName);
726         for (Task rootTask : mRootTasks) {
727             final Activity activity =
728                     rootTask.getActivity((a) -> a.name.equals(fullName) || !a.translucent);
729             if (activity != null) {
730                 if (activity.name.equals(fullName)) {
731                     return false;
732                 }
733                 if (!activity.translucent) {
734                     return true;
735                 }
736             }
737         }
738 
739         return false;
740     }
741 
containsStartedActivities()742     public boolean containsStartedActivities() {
743         for (Task rootTask : mRootTasks) {
744             final Activity activity = rootTask.getActivity(
745                     (a) -> !a.state.equals(STATE_STOPPED) && !a.state.equals(STATE_DESTROYED));
746             if (activity != null) return true;
747         }
748         return false;
749     }
750 
hasActivityState(ComponentName activityName, String activityState)751     boolean hasActivityState(ComponentName activityName, String activityState) {
752         for (Task rootTask : mRootTasks) {
753             final Activity activity = rootTask.getActivity(activityName);
754             if (activity != null) return activity.state.equals(activityState);
755         }
756         return false;
757     }
758 
getActivityProcId(ComponentName activityName)759     int getActivityProcId(ComponentName activityName) {
760         for (Task rootTask : mRootTasks) {
761             final Activity activity = rootTask.getActivity(activityName);
762             if (activity != null) return activity.procId;
763         }
764         return -1;
765     }
766 
isRecentsActivityVisible()767     boolean isRecentsActivityVisible() {
768         final Activity recentsActivity = getRecentsActivity();
769         return recentsActivity != null && recentsActivity.visible;
770     }
771 
getHomeActivityName()772     ComponentName getHomeActivityName() {
773         Activity activity = getHomeActivity();
774         if (activity == null) {
775             return null;
776         }
777         return ComponentName.unflattenFromString(activity.name);
778     }
779 
getDreamTask()780     Task getDreamTask() {
781         final Task dreamRootTask = getRootTaskByActivityType(ACTIVITY_TYPE_DREAM);
782         if (dreamRootTask != null) {
783             return dreamRootTask.getTopTask();
784         }
785         return null;
786     }
787 
getHomeTask()788     Task getHomeTask() {
789         final Task homeRootTask = getRootTaskByActivityType(ACTIVITY_TYPE_HOME);
790         if (homeRootTask != null) {
791             return homeRootTask.getTopTask();
792         }
793         return null;
794     }
795 
getRecentsTask()796     private Task getRecentsTask() {
797         final Task recentsRootTask = getRootTaskByActivityType(ACTIVITY_TYPE_RECENTS);
798         if (recentsRootTask != null) {
799             return recentsRootTask.getTopTask();
800         }
801         return null;
802     }
803 
getHomeActivity()804     private Activity getHomeActivity() {
805         final Task homeTask = getHomeTask();
806         return homeTask != null ? homeTask.mActivities.get(homeTask.mActivities.size() - 1) : null;
807     }
808 
getRecentsActivity()809     private Activity getRecentsActivity() {
810         final Task recentsTask = getRecentsTask();
811         return recentsTask != null ? recentsTask.mActivities.get(recentsTask.mActivities.size() - 1)
812                 : null;
813     }
814 
getRootTaskIdByActivity(ComponentName activityName)815     public int getRootTaskIdByActivity(ComponentName activityName) {
816         final Task task = getTaskByActivity(activityName);
817         return  (task == null) ? INVALID_TASK_ID : task.mRootTaskId;
818     }
819 
getTaskByActivity(ComponentName activityName)820     public Task getTaskByActivity(ComponentName activityName) {
821         return getTaskByActivity(
822                 activityName, WINDOWING_MODE_UNDEFINED, new int[]{ INVALID_TASK_ID });
823     }
824 
getTaskByActivity(ComponentName activityName, int[] excludeTaskIds)825     public Task getTaskByActivity(ComponentName activityName, int[] excludeTaskIds) {
826         return getTaskByActivity(activityName, WINDOWING_MODE_UNDEFINED, excludeTaskIds);
827     }
828 
getTaskByActivity(ComponentName activityName, int windowingMode, int[] excludeTaskIds)829     private Task getTaskByActivity(ComponentName activityName, int windowingMode,
830             int[] excludeTaskIds) {
831         Activity activity = getActivity(activityName, windowingMode, excludeTaskIds);
832         return activity == null ? null : activity.getTask();
833     }
834 
835     @Nullable
getTaskFragmentByActivity(ComponentName activityName)836     public TaskFragment getTaskFragmentByActivity(ComponentName activityName) {
837         return getActivity(activityName).getTaskFragment();
838     }
839 
getActivity(ComponentName activityName)840     public Activity getActivity(ComponentName activityName) {
841         return getActivity(activityName, WINDOWING_MODE_UNDEFINED, new int[]{ INVALID_TASK_ID });
842     }
843 
getActivity(ComponentName activityName, int windowingMode, int[] excludeTaskIds)844     private Activity getActivity(ComponentName activityName, int windowingMode,
845             int[] excludeTaskIds) {
846         for (Task rootTask : mRootTasks) {
847             if (windowingMode == WINDOWING_MODE_UNDEFINED
848                     || windowingMode == rootTask.getWindowingMode()) {
849                 Activity activity = rootTask.getActivity(activityName, excludeTaskIds);
850                 if (activity != null) return activity;
851             }
852         }
853         return null;
854     }
855 
856     /**
857      * Get the number of activities in the task, with the option to count only activities with
858      * specific name.
859      * @param taskId Id of the task where we're looking for the number of activities.
860      * @param activityName Optional name of the activity we're interested in.
861      * @return Number of all activities in the task if activityName is {@code null}, otherwise will
862      *         report number of activities that have specified name.
863      */
getActivityCountInTask(int taskId, @Nullable ComponentName activityName)864     public int getActivityCountInTask(int taskId, @Nullable ComponentName activityName) {
865         // If activityName is null, count all activities in the task.
866         // Otherwise count activities that have specified name.
867         for (Task rootTask : mRootTasks) {
868             final Task task = rootTask.getTask(taskId);
869             if (task == null) continue;
870 
871             if (activityName == null) {
872                 return task.mActivities.size();
873             }
874             final String fullName = getActivityName(activityName);
875             int count = 0;
876             for (Activity activity : task.mActivities) {
877                 if (activity.name.equals(fullName)) {
878                     count++;
879                 }
880             }
881             return count;
882         }
883         return 0;
884     }
885 
getRootTasksCount()886     public int getRootTasksCount() {
887         return mRootTasks.size();
888     }
889 
getRootTasksCount(int displayId)890     public int getRootTasksCount(int displayId) {
891         return getRootTasksCount(t -> t.mDisplayId == displayId);
892     }
893 
894     /**
895      * Count root tasks filtered by the predicate passed as argument.
896      */
getRootTasksCount(Predicate<? super Task> predicate)897     public int getRootTasksCount(Predicate<? super Task> predicate) {
898         return (int) mRootTasks.stream().filter(predicate).count();
899     }
900 
pendingActivityContain(ComponentName activityName)901     boolean pendingActivityContain(ComponentName activityName) {
902         return mPendingActivities.contains(getActivityName(activityName));
903     }
904 
905     // Get the logical display size of the default display.
getLogicalDisplaySize()906     public static Point getLogicalDisplaySize() {
907         WindowManagerState mWmState = new WindowManagerState();
908         mWmState.computeState();
909         Rect size = mWmState.getDisplay(DEFAULT_DISPLAY).getDisplayRect();
910         return new Point(size.width(), size.height());
911     }
912 
getDefaultDisplayLastTransition()913     String getDefaultDisplayLastTransition() {
914         return getDisplay(DEFAULT_DISPLAY).getLastTransition();
915     }
916 
getDefaultDisplayAppTransitionState()917     String getDefaultDisplayAppTransitionState() {
918         return getDisplay(DEFAULT_DISPLAY).getAppTransitionState();
919     }
920 
getMatchingVisibleWindowState(final String windowName)921     public List<WindowState> getMatchingVisibleWindowState(final String windowName) {
922         return getMatchingWindows(ws -> ws.isSurfaceShown() && windowName.equals(ws.getName()))
923                 .collect(Collectors.toList());
924     }
925 
getMatchingWindows(Predicate<WindowState> condition)926     private Stream<WindowState> getMatchingWindows(Predicate<WindowState> condition) {
927         return mWindowStates.stream().filter(condition);
928     }
929 
930     @Nullable
getWindowByPackageName(String packageName, int windowType)931     public WindowState getWindowByPackageName(String packageName, int windowType) {
932         final List<WindowState> windowList = getWindowsByPackageName(packageName, windowType);
933         return windowList.isEmpty() ? null : windowList.get(0);
934     }
935 
getWindowsByPackageName(String packageName, int... restrictToTypes)936     public List<WindowState> getWindowsByPackageName(String packageName, int... restrictToTypes) {
937         return getMatchingWindows(ws ->
938                 (ws.getName().equals(packageName) || ws.getName().startsWith(packageName + "/"))
939                         && Arrays.stream(restrictToTypes).anyMatch(type -> type == ws.getType()))
940                 .collect(Collectors.toList());
941     }
942 
hasNotificationShade()943     public boolean hasNotificationShade() {
944         computeState();
945         return !getMatchingWindowType(TYPE_NOTIFICATION_SHADE).isEmpty();
946     }
947 
getWindows()948     List<WindowState> getWindows() {
949         return new ArrayList<>(mWindowStates);
950     }
951 
getMatchingWindowType(int type)952     List<WindowState> getMatchingWindowType(int type) {
953         return getMatchingWindows(ws -> type == ws.mType).collect(Collectors.toList());
954     }
955 
getMatchingWindowTokens(final String windowName)956     List<String> getMatchingWindowTokens(final String windowName) {
957         return getMatchingWindows(ws -> windowName.equals(ws.getName()))
958                 .map(WindowState::getToken)
959                 .collect(Collectors.toList());
960     }
961 
getAllNavigationBarStates()962     List<WindowState> getAllNavigationBarStates() {
963         return getMatchingWindows(WindowManagerState::isValidNavBarType)
964                 .collect(Collectors.toList());
965     }
966 
967     @Nullable
getAndAssertNavBarWindowsOnDisplay(int displayId, int expectedNavBarCount)968     List<WindowState> getAndAssertNavBarWindowsOnDisplay(int displayId, int expectedNavBarCount) {
969         List<WindowState> navWindows = getMatchingWindows(ws -> isValidNavBarType(ws)
970                 && ws.getDisplayId() == displayId)
971                 .filter(Objects::nonNull)
972                 .collect(Collectors.toList());
973         // We may need some time to wait for nav bar showing.
974         // It's Ok to get less that expected nav bars here.
975         assertTrue("There should be at most expectedNavBarCount navigation bar on a display",
976                 navWindows.size() <= expectedNavBarCount);
977 
978         return navWindows.size() == expectedNavBarCount ? navWindows : null;
979     }
980 
getWindowStateForAppToken(String appToken)981     WindowState getWindowStateForAppToken(String appToken) {
982         return getMatchingWindows(ws -> ws.getToken().equals(appToken))
983                 .findFirst()
984                 .orElse(null);
985     }
986 
getFrontWindow()987     String getFrontWindow() {
988         if (mWindowStates == null || mWindowStates.isEmpty()) {
989             return null;
990         }
991         return mWindowStates.get(0).getName();
992     }
993 
994     /** Check if there exists a window record with matching windowName. */
containsWindow(String windowName)995     public boolean containsWindow(String windowName) {
996         for (WindowState window : mWindowStates) {
997             if (window.getName().equals(windowName)) {
998                 return true;
999             }
1000         }
1001         return false;
1002     }
1003 
1004     /** Check if at least one window which matches the specified name has shown it's surface. */
isWindowSurfaceShown(String windowName)1005     public boolean isWindowSurfaceShown(String windowName) {
1006         for (WindowState window : mWindowStates) {
1007             if (window.getName().equals(windowName)) {
1008                 if (window.isSurfaceShown()) {
1009                     return true;
1010                 }
1011             }
1012         }
1013         return false;
1014     }
1015 
1016     /** Check if at least one window which matches provided window name is visible. */
isWindowVisible(String windowName)1017     public boolean isWindowVisible(String windowName) {
1018         for (WindowState window : mWindowStates) {
1019             if (window.getName().equals(windowName)) {
1020                 if (window.isVisible()) {
1021                     return true;
1022                 }
1023             }
1024         }
1025         return false;
1026     }
1027 
allWindowSurfacesShown(String windowName)1028     public boolean allWindowSurfacesShown(String windowName) {
1029         boolean allShown = false;
1030         for (WindowState window : mWindowStates) {
1031             if (window.getName().equals(windowName)) {
1032                 if (!window.isSurfaceShown()) {
1033                     log("[VISIBLE] not visible" + windowName);
1034                     return false;
1035                 }
1036                 log("[VISIBLE] visible" + windowName);
1037                 allShown = true;
1038             }
1039         }
1040         return allShown;
1041     }
1042 
1043     /** Checks whether the display contains the given activity. */
hasActivityInDisplay(int displayId, ComponentName activityName)1044     boolean hasActivityInDisplay(int displayId, ComponentName activityName) {
1045         for (Task rootTask : getDisplay(displayId).getRootTasks()) {
1046             if (rootTask.containsActivity(activityName)) {
1047                 return true;
1048             }
1049         }
1050         return false;
1051     }
1052 
findFirstWindowWithType(int type)1053     WindowState findFirstWindowWithType(int type) {
1054         for (WindowState window : mWindowStates) {
1055             if (window.getType() == type) {
1056                 return window;
1057             }
1058         }
1059         return null;
1060     }
1061 
getZOrder(WindowState w)1062     public int getZOrder(WindowState w) {
1063         return mWindowStates.size() - mWindowStates.indexOf(w);
1064     }
1065 
getStandardRootTaskByWindowingMode(int windowingMode)1066     Task getStandardRootTaskByWindowingMode(int windowingMode) {
1067         for (Task task : mRootTasks) {
1068             if (task.getActivityType() != ACTIVITY_TYPE_STANDARD) {
1069                 continue;
1070             }
1071             if (task.getWindowingMode() == windowingMode) {
1072                 return task;
1073             }
1074         }
1075         return null;
1076     }
1077 
getInputMethodWindowState()1078     WindowManagerState.WindowState getInputMethodWindowState() {
1079         return getWindowStateForAppToken(mInputMethodWindowAppToken);
1080     }
1081 
isDisplayFrozen()1082     public boolean isDisplayFrozen() {
1083         return mDisplayFrozen;
1084     }
1085 
getRotation()1086     public int getRotation() {
1087         return getDisplay(DEFAULT_DISPLAY).mRotation;
1088     }
1089 
getLastOrientation()1090     public int getLastOrientation() {
1091         return getDisplay(DEFAULT_DISPLAY).mLastOrientation;
1092     }
1093 
getFocusedDisplayId()1094     public int getFocusedDisplayId() {
1095         return mFocusedDisplayId;
1096     }
1097 
1098     public static class DisplayContent extends DisplayArea {
1099         public int mId;
1100         ArrayList<Task> mRootTasks = new ArrayList<>();
1101         int mFocusedRootTaskId;
1102         String mResumedActivity;
1103         boolean mSingleTaskInstance;
1104         Rect mDefaultPinnedStackBounds = null;
1105         Rect mPinnedStackMovementBounds = null;
1106 
1107         private Rect mDisplayRect = new Rect();
1108         private Rect mAppRect = new Rect();
1109         private int mDpi;
1110         private int mFlags;
1111         private String mName;
1112         private int mSurfaceSize;
1113         private String mFocusedApp;
1114         private String mLastTransition;
1115         private String mAppTransitionState;
1116         private int mRotation;
1117         private boolean mFrozenToUserRotation;
1118         private int mUserRotation;
1119         private int mFixedToUserRotationMode;
1120         private int mLastOrientation;
1121 
DisplayContent(DisplayContentProto proto)1122         DisplayContent(DisplayContentProto proto) {
1123             super(proto.rootDisplayArea);
1124             mId = proto.id;
1125             mFocusedRootTaskId = proto.focusedRootTaskId;
1126             mSingleTaskInstance = proto.singleTaskInstance;
1127             if (proto.resumedActivity != null) {
1128                 mResumedActivity = proto.resumedActivity.title;
1129             }
1130             addRootTasks();
1131 
1132             mDpi = proto.dpi;
1133             DisplayInfoProto infoProto = proto.displayInfo;
1134             if (infoProto != null) {
1135                 mDisplayRect.set(0, 0, infoProto.logicalWidth, infoProto.logicalHeight);
1136                 mAppRect.set(0, 0, infoProto.appWidth, infoProto.appHeight);
1137                 mName = infoProto.name;
1138                 mFlags = infoProto.flags;
1139             }
1140             final DisplayFramesProto displayFramesProto = proto.displayFrames;
1141             mSurfaceSize = proto.surfaceSize;
1142             mFocusedApp = proto.focusedApp;
1143 
1144             final AppTransitionProto appTransitionProto = proto.appTransition;
1145             int appState = 0;
1146             int lastTransition = 0;
1147             if (appTransitionProto != null) {
1148                 appState = appTransitionProto.appTransitionState;
1149                 lastTransition = appTransitionProto.lastUsedAppTransition;
1150             }
1151             mAppTransitionState = appStateToString(appState);
1152             mLastTransition = appTransitionToString(lastTransition);
1153 
1154             PinnedTaskControllerProto pinnedTaskProto = proto.pinnedTaskController;
1155             if (pinnedTaskProto != null) {
1156                 mDefaultPinnedStackBounds = extract(pinnedTaskProto.defaultBounds);
1157                 mPinnedStackMovementBounds = extract(pinnedTaskProto.movementBounds);
1158             }
1159 
1160             final DisplayRotationProto rotationProto = proto.displayRotation;
1161             if (rotationProto != null) {
1162                 mRotation = rotationProto.rotation;
1163                 mFrozenToUserRotation = rotationProto.frozenToUserRotation;
1164                 mUserRotation = rotationProto.userRotation;
1165                 mFixedToUserRotationMode = rotationProto.fixedToUserRotationMode;
1166                 mLastOrientation = rotationProto.lastOrientation;
1167             }
1168         }
1169 
getName()1170         public String getName() {
1171             return mName;
1172         }
1173 
addRootTasks()1174         private void addRootTasks() {
1175             // TODO(b/149338177): figure out how CTS tests deal with organizer. For now,
1176             //                    don't treat them as regular root tasks
1177             collectDescendantsOfTypeIf(Task.class, t -> t.isRootTask(), this,
1178                     mRootTasks);
1179             ArrayList<Task> rootOrganizedTasks = new ArrayList<>();
1180             for (int i = mRootTasks.size() -1; i >= 0; --i) {
1181                 final Task task = mRootTasks.get(i);
1182                 // Skip tasks created by an organizer
1183                 if (task.mCreatedByOrganizer) {
1184                     mRootTasks.remove(task);
1185                     rootOrganizedTasks.add(task);
1186                 }
1187             }
1188             // Add root tasks controlled by an organizer
1189             while (rootOrganizedTasks.size() > 0) {
1190                 final Task task = rootOrganizedTasks.remove(0);
1191                 for (int i = task.mChildren.size() - 1; i >= 0; i--) {
1192                     final Task child = (Task) task.mChildren.get(i);
1193                     if (!child.mCreatedByOrganizer) {
1194                         mRootTasks.add(child);
1195                     } else {
1196                         rootOrganizedTasks.add(child);
1197                     }
1198                 }
1199             }
1200         }
1201 
containsActivity(ComponentName activityName)1202         boolean containsActivity(ComponentName activityName) {
1203             for (Task task : mRootTasks) {
1204                 if (task.containsActivity(activityName)) return true;
1205             }
1206             return false;
1207         }
1208 
getAllTaskDisplayAreas()1209         List<DisplayArea> getAllTaskDisplayAreas() {
1210             final List<DisplayArea> taskDisplayAreas = new ArrayList<>();
1211             collectDescendantsOfTypeIf(DisplayArea.class, DisplayArea::isTaskDisplayArea, this,
1212                     taskDisplayAreas);
1213             return taskDisplayAreas;
1214         }
1215 
1216         @Nullable
getTaskDisplayArea(ComponentName activityName)1217         DisplayArea getTaskDisplayArea(ComponentName activityName) {
1218             final List<DisplayArea> taskDisplayAreas = getAllTaskDisplayAreas();
1219             List<DisplayArea> result = taskDisplayAreas.stream().filter(
1220                     tda -> tda.containsActivity(activityName))
1221                     .collect(Collectors.toList());
1222 
1223             assertWithMessage("There must be exactly one activity among all TaskDisplayAreas.")
1224                     .that(result.size()).isAtMost(1);
1225 
1226             return result.stream().findFirst().orElse(null);
1227         }
1228 
getAllChildDisplayAreas()1229         List<DisplayArea> getAllChildDisplayAreas() {
1230             final List<DisplayArea> displayAreas = new ArrayList<>();
1231             collectDescendantsOfType(DisplayArea.class,this, displayAreas);
1232             return displayAreas;
1233         }
1234 
1235         @Nullable
getDisplayArea(String windowName)1236         DisplayArea getDisplayArea(String windowName) {
1237             List<DisplayArea> displayAreas = new ArrayList<>();
1238             final Predicate<DisplayArea> p = da -> {
1239                 final boolean containsChildWindowToken = !da.mChildren.isEmpty()
1240                         && da.mChildren.get(0) instanceof WindowToken;
1241                 return !da.isTaskDisplayArea() && containsChildWindowToken;
1242             };
1243             collectDescendantsOfTypeIf(DisplayArea.class, p, this, displayAreas);
1244             List<DisplayArea> result = displayAreas.stream().filter(
1245                     da -> da.containsWindow(windowName))
1246                     .collect(Collectors.toList());
1247 
1248             assertWithMessage("There must be exactly one window among all DisplayAreas.")
1249                     .that(result.size()).isAtMost(1);
1250 
1251             return result.stream().findFirst().orElse(null);
1252         }
1253 
getRootTasks()1254         ArrayList<Task> getRootTasks() {
1255             return mRootTasks;
1256         }
1257 
getDpi()1258         int getDpi() {
1259             return mDpi;
1260         }
1261 
getDisplayRect()1262         Rect getDisplayRect() {
1263             return mDisplayRect;
1264         }
1265 
getAppRect()1266         public Rect getAppRect() {
1267             return mAppRect;
1268         }
1269 
getFlags()1270         int getFlags() {
1271             return mFlags;
1272         }
1273 
getSurfaceSize()1274         int getSurfaceSize() {
1275             return mSurfaceSize;
1276         }
1277 
getFocusedApp()1278         String getFocusedApp() {
1279             return mFocusedApp;
1280         }
1281 
getLastTransition()1282         String getLastTransition() { return mLastTransition; }
1283 
getAppTransitionState()1284         String getAppTransitionState() { return mAppTransitionState; }
1285 
1286         @Override
toString()1287         public String toString() {
1288             return "Display #" + mId + ": name=" + mName + " mDisplayRect=" + mDisplayRect
1289                     + " mAppRect=" + mAppRect + " mFlags=" + mFlags;
1290         }
1291     }
1292 
1293     public static class Task extends ActivityContainer {
1294         int mTaskId;
1295         int mRootTaskId;
1296         public int mDisplayId;
1297         Rect mLastNonFullscreenBounds;
1298         String mRealActivity;
1299         String mOrigActivity;
1300         ArrayList<Task> mTasks = new ArrayList<>();
1301         /** Contains TaskFragment but not Task children */
1302         ArrayList<TaskFragment> mTaskFragments = new ArrayList<>();
1303         ArrayList<Activity> mActivities = new ArrayList<>();
1304         int mTaskType;
1305         private int mResizeMode;
1306         String mResumedActivity;
1307         boolean mAnimatingBounds;
1308         private int mSurfaceWidth;
1309         private int mSurfaceHeight;
1310         boolean mCreatedByOrganizer;
1311         String mAffinity;
1312         boolean mHasChildPipActivity;
1313         WindowContainer mParent;
1314 
Task(TaskProto proto, WindowContainer parent)1315         Task(TaskProto proto, WindowContainer parent) {
1316             super(proto.taskFragment.windowContainer);
1317             mTaskId = proto.id;
1318             mRootTaskId = proto.rootTaskId;
1319             mParent = parent;
1320             mDisplayId = proto.taskFragment.displayId;
1321             mLastNonFullscreenBounds = extract(proto.lastNonFullscreenBounds);
1322             mRealActivity = proto.realActivity;
1323             mOrigActivity = proto.origActivity;
1324             mTaskType = proto.taskFragment.activityType;
1325             mResizeMode = proto.resizeMode;
1326             mFullscreen = proto.fillsParent;
1327             mBounds = extract(proto.bounds);
1328             mMinWidth = proto.taskFragment.minWidth;
1329             mMinHeight = proto.taskFragment.minHeight;
1330             mAnimatingBounds = proto.animatingBounds;
1331             mSurfaceWidth = proto.surfaceWidth;
1332             mSurfaceHeight = proto.surfaceHeight;
1333             mCreatedByOrganizer = proto.createdByOrganizer;
1334             mAffinity = proto.affinity;
1335             mHasChildPipActivity = proto.hasChildPipActivity;
1336 
1337             if (proto.resumedActivity != null) {
1338                 mResumedActivity = proto.resumedActivity.title;
1339             }
1340 
1341             collectChildrenOfType(Task.class, this, mTasks);
1342             collectChildrenOfType(TaskFragment.class, this, mTaskFragments);
1343             collectChildrenOfType(Activity.class, this, mActivities);
1344         }
1345 
isEmpty()1346         boolean isEmpty() {
1347             return mTasks.isEmpty() && mTaskFragments.isEmpty() && mActivities.isEmpty();
1348         }
1349 
1350         /** Gets the pure parent TaskFragment if exist. */
getParentTaskFragment()1351         public TaskFragment getParentTaskFragment() {
1352             if (mParent instanceof TaskFragment) {
1353                 return (TaskFragment) mParent;
1354             }
1355             if (mParent instanceof Task) {
1356                 return ((Task) mParent).getParentTaskFragment();
1357             }
1358             // If the parent is a TaskDisplayArea, it means this Task doesn't have TaskFragment
1359             // parent.
1360             return null;
1361         }
1362 
getResizeMode()1363         public int getResizeMode() {
1364             return mResizeMode;
1365         }
1366 
getTaskId()1367         public int getTaskId() {
1368             return mTaskId;
1369         }
isRootTask()1370         boolean isRootTask() {
1371             return mTaskId == mRootTaskId;
1372         }
1373 
isLeafTask()1374         boolean isLeafTask() {
1375             return mTasks.size() == 0;
1376         }
1377 
getRootTaskId()1378         public int getRootTaskId() {
1379             return mRootTaskId;
1380         }
1381 
getSurfaceWidth()1382         int getSurfaceWidth() {
1383             return mSurfaceWidth;
1384         }
1385 
getSurfaceHeight()1386         int getSurfaceHeight() {
1387             return mSurfaceHeight;
1388         }
1389 
getAffinity()1390         public String getAffinity() { return mAffinity; }
1391 
getActivities()1392         public ArrayList<Activity> getActivities() {
1393             return mActivities;
1394         }
1395 
1396         /** @return the top task in the root task. */
getTopTask()1397         Task getTopTask() {
1398             // NOTE: Unlike the WindowManager internals, we dump the state from top to bottom,
1399             //       so the indices are inverted
1400             return getTask((t) -> true);
1401         }
1402 
getResumedActivity()1403         public String getResumedActivity() {
1404             return mResumedActivity;
1405         }
1406 
getTasks()1407         public List<Task> getTasks() {
1408             return new ArrayList<>(mTasks);
1409         }
1410 
1411         /** Returns non-Task leaf {@link TaskFragment} list. */
getTaskFragments()1412         public List<TaskFragment> getTaskFragments() {
1413             return new ArrayList<>(mTaskFragments);
1414         }
1415 
getTask(Predicate<Task> predicate)1416         Task getTask(Predicate<Task> predicate) {
1417             for (Task task : mTasks) {
1418                 if (predicate.test(task)) return task;
1419             }
1420             return predicate.test(this) ? this : null;
1421         }
1422 
getTask(int taskId)1423         Task getTask(int taskId) {
1424             return getTask((t) -> t.mTaskId == taskId);
1425         }
1426 
forAllTasks(Consumer<Task> consumer)1427         void forAllTasks(Consumer<Task> consumer) {
1428             for (Task task : mTasks) {
1429                 consumer.accept(task);
1430             }
1431             consumer.accept(this);
1432         }
1433 
getActivity(Predicate<Activity> predicate)1434         Activity getActivity(Predicate<Activity> predicate) {
1435             for (Activity activity : mActivities) {
1436                 if (predicate.test(activity)) return activity;
1437             }
1438             for (TaskFragment taskFragment : mTaskFragments) {
1439                 final Activity activity = taskFragment.getActivity(predicate);
1440                 if (activity != null) return activity;
1441             }
1442             for (Task task : mTasks) {
1443                 final Activity activity = task.getActivity(predicate);
1444                 if (activity != null) return activity;
1445             }
1446             return null;
1447         }
1448 
getActivity(ComponentName activityName)1449         public Activity getActivity(ComponentName activityName) {
1450             final String fullName = getActivityName(activityName);
1451             return getActivity((activity) -> activity.name.equals(fullName));
1452         }
1453 
getActivity(ComponentName activityName, int[] excludeTaskIds)1454         public Activity getActivity(ComponentName activityName, int[] excludeTaskIds) {
1455             final String fullName = getActivityName(activityName);
1456             return getActivity((activity) -> {
1457                 if (!activity.name.equals(fullName)) {
1458                     return false;
1459                 }
1460                 for (int excludeTaskId : excludeTaskIds) {
1461                     if (activity.getTask().mTaskId == excludeTaskId) {
1462                         return false;
1463                     }
1464                 }
1465                 return true;
1466             });
1467         }
1468 
containsActivity(ComponentName activityName)1469         boolean containsActivity(ComponentName activityName) {
1470             return getActivity(activityName) != null;
1471         }
1472 
1473         @Override
getActivityType()1474         int getActivityType() {
1475             return mTaskType;
1476         }
1477     }
1478 
1479     public static class TaskFragment extends ActivityContainer {
1480         public int mDisplayId;
1481         Task mParentTask;
1482         ArrayList<Task> mTasks = new ArrayList<>();
1483         ArrayList<TaskFragment> mTaskFragments = new ArrayList<>();
1484         ArrayList<Activity> mActivities = new ArrayList<>();
1485         int mTaskFragmentType;
1486 
1487         TaskFragment(TaskFragmentProto proto, WindowContainer parent) {
1488             super(proto.windowContainer);
1489             mParentTask = (Task) parent;
1490             mDisplayId = proto.displayId;
1491             mTaskFragmentType = proto.activityType;
1492             mMinWidth = proto.minWidth;
1493             mMinHeight = proto.minHeight;
1494 
1495             collectChildrenOfType(Task.class, this, mTasks);
1496             collectChildrenOfType(TaskFragment.class, this, mTaskFragments);
1497             collectChildrenOfType(Activity.class, this, mActivities);
1498         }
1499 
1500         public List<Task> getTasks() {
1501             return mTasks;
1502         }
1503 
1504         /** Returns non-Task TaskFragment children. */
1505         public List<TaskFragment> getTaskFragments() {
1506             return mTaskFragments;
1507         }
1508 
1509         public List<Activity> getActivities() {
1510             return mActivities;
1511         }
1512 
1513         Activity getActivity(Predicate<Activity> predicate) {
1514             for (Activity activity : mActivities) {
1515                 if (predicate.test(activity)) {
1516                     return activity;
1517                 }
1518             }
1519             for (TaskFragment taskFragment : mTaskFragments) {
1520                 final Activity activity = taskFragment.getActivity(predicate);
1521                 if (activity != null) {
1522                     return activity;
1523                 }
1524             }
1525             for (Task task : mTasks) {
1526                 final Activity activity = task.getActivity(predicate);
1527                 if (activity != null) {
1528                     return activity;
1529                 }
1530             }
1531             return null;
1532         }
1533 
1534         @Override
1535         int getActivityType() {
1536             return mTaskFragmentType;
1537         }
1538     }
1539 
1540     public static class Activity extends ActivityContainer {
1541 
1542         String name;
1543         String state;
1544         boolean visible;
1545         boolean frontOfTask;
1546         boolean inSizeCompatMode;
1547         float minAspectRatio;
1548         boolean providesMaxBounds;
1549         int procId = -1;
1550         public boolean translucent;
1551         private WindowContainer mParent;
1552 
1553         Activity(ActivityRecordProto proto, WindowContainer parent) {
1554             super(proto.windowToken.windowContainer);
1555             name = proto.name;
1556             state = proto.state;
1557             visible = proto.visible;
1558             frontOfTask = proto.frontOfTask;
1559             inSizeCompatMode = proto.inSizeCompatMode;
1560             minAspectRatio = proto.minAspectRatio;
1561             providesMaxBounds = proto.providesMaxBounds;
1562             if (proto.procId != 0) {
1563                 procId = proto.procId;
1564             }
1565             translucent = proto.translucent;
1566             mParent = parent;
1567         }
1568 
1569         @NonNull
1570         public Task getTask() {
1571             if (mParent instanceof Task) {
1572                 return (Task) mParent;
1573             }
1574             return ((TaskFragment) mParent).mParentTask;
1575         }
1576 
1577         @Nullable
1578         public TaskFragment getTaskFragment() {
1579             if (mParent instanceof TaskFragment) {
1580                 return (TaskFragment) mParent;
1581             }
1582             return ((Task) mParent).getParentTaskFragment();
1583         }
1584 
1585         public String getName() {
1586             return name;
1587         }
1588 
1589         public String getState() {
1590             return state;
1591         }
1592 
1593         public boolean inSizeCompatMode() {
1594             return inSizeCompatMode;
1595         }
1596 
1597         public float getMinAspectRatio() {
1598             return minAspectRatio;
1599         }
1600 
1601         public boolean providesMaxBounds() {
1602             return providesMaxBounds;
1603         }
1604 
1605         @Override
1606         public Rect getBounds() {
1607             if (mBounds == null) {
1608                 return mFullConfiguration.windowConfiguration.getBounds();
1609             }
1610             return mBounds;
1611         }
1612 
1613         public Rect getMaxBounds() {
1614             return mFullConfiguration.windowConfiguration.getMaxBounds();
1615         }
1616 
1617         public Rect getAppBounds() {
1618             return mFullConfiguration.windowConfiguration.getAppBounds();
1619         }
1620     }
1621 
1622     static abstract class ActivityContainer extends WindowContainer {
1623         protected boolean mFullscreen;
1624         protected Rect mBounds;
1625         protected int mMinWidth = -1;
1626         protected int mMinHeight = -1;
1627 
1628         ActivityContainer(WindowContainerProto proto) {
1629             super(proto);
1630         }
1631 
1632         public Rect getBounds() {
1633             return mBounds;
1634         }
1635 
1636         boolean isFullscreen() {
1637             return mFullscreen;
1638         }
1639 
1640         int getMinWidth() {
1641             return mMinWidth;
1642         }
1643 
1644         int getMinHeight() {
1645             return mMinHeight;
1646         }
1647     }
1648 
1649     static class KeyguardControllerState {
1650 
1651         boolean aodShowing = false;
1652         boolean keyguardShowing = false;
1653         SparseArray<Boolean> mKeyguardOccludedStates = new SparseArray<>();
1654 
1655         KeyguardControllerState(KeyguardControllerProto proto) {
1656             if (proto != null) {
1657                 aodShowing = proto.aodShowing;
1658                 keyguardShowing = proto.keyguardShowing;
1659                 for (int i = 0;  i < proto.keyguardOccludedStates.length; i++) {
1660                     mKeyguardOccludedStates.append(proto.keyguardOccludedStates[i].displayId,
1661                             proto.keyguardOccludedStates[i].keyguardOccluded);
1662                 }
1663             }
1664         }
1665 
1666         boolean isKeyguardOccluded(int displayId) {
1667             if (mKeyguardOccludedStates.get(displayId) != null) {
1668                 return mKeyguardOccludedStates.get(displayId);
1669             }
1670             return false;
1671         }
1672     }
1673 
1674     static class ConfigurationContainer {
1675         final Configuration mOverrideConfiguration = new Configuration();
1676         final Configuration mFullConfiguration = new Configuration();
1677         final Configuration mMergedOverrideConfiguration = new Configuration();
1678 
1679         ConfigurationContainer(ConfigurationContainerProto proto) {
1680             if (proto == null) {
1681                 return;
1682             }
1683             mOverrideConfiguration.setTo(extract(proto.overrideConfiguration));
1684             mFullConfiguration.setTo(extract(proto.fullConfiguration));
1685             mMergedOverrideConfiguration.setTo(extract(proto.mergedOverrideConfiguration));
1686         }
1687 
1688         boolean isWindowingModeCompatible(int requestedWindowingMode) {
1689             if (requestedWindowingMode == WINDOWING_MODE_UNDEFINED) {
1690                 return true;
1691             }
1692             return getWindowingMode() == requestedWindowingMode;
1693         }
1694 
1695         public int getWindowingMode() {
1696             if (mFullConfiguration == null) {
1697                 return WINDOWING_MODE_UNDEFINED;
1698             }
1699             return mFullConfiguration.windowConfiguration.getWindowingMode();
1700         }
1701 
1702         int getActivityType() {
1703             if (mFullConfiguration == null) {
1704                 return ACTIVITY_TYPE_UNDEFINED;
1705             }
1706             return mFullConfiguration.windowConfiguration.getActivityType();
1707         }
1708     }
1709 
1710     public static class RootWindowContainer extends WindowContainer {
1711         RootWindowContainer(RootWindowContainerProto proto) {
1712             super(proto.windowContainer);
1713         }
1714     }
1715     public static class DisplayArea extends WindowContainer {
1716         private final boolean mIsTaskDisplayArea;
1717         private final boolean mIsRootDisplayArea;
1718         private final int mFeatureId;
1719         private final boolean mIsOrganized;
1720         private ArrayList<Activity> mActivities;
1721         private final ArrayList<WindowState> mWindows = new ArrayList<>();
1722 
1723         DisplayArea(DisplayAreaProto proto) {
1724             super(proto.windowContainer);
1725             mIsTaskDisplayArea = proto.isTaskDisplayArea;
1726             mIsRootDisplayArea = proto.isRootDisplayArea;
1727             mFeatureId = proto.featureId;
1728             mIsOrganized = proto.isOrganized;
1729             if (mIsTaskDisplayArea) {
1730                 mActivities = new ArrayList<>();
1731                 collectDescendantsOfType(Activity.class, this, mActivities);
1732             }
1733             collectDescendantsOfType(WindowState.class, this, mWindows);
1734         }
1735 
1736         boolean isTaskDisplayArea() {
1737             return mIsTaskDisplayArea;
1738         }
1739 
1740         boolean isRootDisplayArea() {
1741             return mIsRootDisplayArea;
1742         }
1743 
1744         int getFeatureId() {
1745             return mFeatureId;
1746         }
1747 
1748         boolean isOrganized() {
1749             return mIsOrganized;
1750         }
1751 
1752         @Override
1753         public Rect getBounds() {
1754             if (mBounds == null) {
1755                 return mFullConfiguration.windowConfiguration.getBounds();
1756             }
1757             return mBounds;
1758         }
1759 
1760         boolean containsActivity(ComponentName activityName) {
1761             if (!mIsTaskDisplayArea) {
1762                 return false;
1763             }
1764 
1765             final String fullName = getActivityName(activityName);
1766             for (Activity a : mActivities) {
1767                 if (a.name.equals(fullName)) {
1768                     return true;
1769                 }
1770             }
1771             return false;
1772         }
1773 
1774         boolean containsWindow(String windowName) {
1775             for (WindowState w : mWindows) {
1776                 if (w.mName.equals(windowName)) {
1777                     return true;
1778                 }
1779             }
1780             return false;
1781         }
1782     }
1783     public static class WindowToken extends WindowContainer {
1784         WindowToken(WindowTokenProto proto) {
1785             super(proto.windowContainer);
1786         }
1787     }
1788 
1789     /**
1790      * Represents WindowContainer classes such as DisplayContent.WindowContainers and
1791      * DisplayContent.NonAppWindowContainers. This can be expanded into a specific class
1792      * if we need track and assert some state in the future.
1793      */
1794     public static class GenericWindowContainer extends WindowContainer {
1795         GenericWindowContainer(WindowContainerProto proto) {
1796             super(proto);
1797         }
1798     }
1799 
1800     static WindowContainer getWindowContainer(WindowContainerChildProto proto,
1801             WindowContainer parent) {
1802         if (proto.displayContent != null) {
1803             return new DisplayContent(proto.displayContent);
1804         }
1805 
1806         if (proto.displayArea != null) {
1807             return new DisplayArea(proto.displayArea);
1808         }
1809 
1810         if (proto.task != null) {
1811             return new Task(proto.task, parent);
1812         }
1813 
1814         if (proto.taskFragment != null) {
1815             return new TaskFragment(proto.taskFragment, parent);
1816         }
1817 
1818         if (proto.activity != null) {
1819             return new Activity(proto.activity, parent);
1820         }
1821 
1822         if (proto.windowToken != null) {
1823             return new WindowToken(proto.windowToken);
1824         }
1825 
1826         if (proto.window != null) {
1827             return new WindowState(proto.window);
1828         }
1829 
1830         if (proto.windowContainer != null) {
1831             return new GenericWindowContainer(proto.windowContainer);
1832         }
1833         return null;
1834     }
1835 
1836     static abstract class WindowContainer extends ConfigurationContainer {
1837 
1838         protected String mName;
1839         protected final String mAppToken;
1840         protected boolean mFullscreen;
1841         protected Rect mBounds;
1842         protected int mOrientation;
1843         protected boolean mVisible;
1844         protected List<WindowState> mSubWindows = new ArrayList<>();
1845         protected List<WindowContainer> mChildren = new ArrayList<>();
1846 
1847         WindowContainer(WindowContainerProto proto) {
1848             super(proto.configurationContainer);
1849             IdentifierProto identifierProto = proto.identifier;
1850             mName = identifierProto.title;
1851             mAppToken = Integer.toHexString(identifierProto.hashCode);
1852             mOrientation = proto.orientation;
1853             for (int i = 0; i < proto.children.length; i++) {
1854                 final WindowContainer child = getWindowContainer(proto.children[i], this);
1855                 if (child != null) {
1856                     mChildren.add(child);
1857                 }
1858             }
1859             mVisible = proto.visible;
1860         }
1861 
1862         @NonNull
1863         public String getName() {
1864             return mName;
1865         }
1866 
1867         @NonNull
1868         public String getPackageName() {
1869             int sep = mName.indexOf('/');
1870             return sep == -1 ? mName : mName.substring(0, sep);
1871         }
1872 
1873         String getToken() {
1874             return mAppToken;
1875         }
1876 
1877         Rect getBounds() {
1878             return mBounds;
1879         }
1880 
1881         boolean isFullscreen() {
1882             return mFullscreen;
1883         }
1884 
1885         boolean isVisible() {
1886             return mVisible;
1887         }
1888 
1889         List<WindowState> getWindows() {
1890             return mSubWindows;
1891         }
1892     }
1893 
1894     public static class WindowState extends WindowContainer {
1895 
1896         private static final int WINDOW_TYPE_NORMAL = 0;
1897         public static final int WINDOW_TYPE_STARTING = 1;
1898         private static final int WINDOW_TYPE_EXITING = 2;
1899         private static final int WINDOW_TYPE_DEBUGGER = 3;
1900 
1901         private final int mWindowType;
1902         private int mType = 0;
1903         private int mDisplayId;
1904         private int mStackId;
1905         private int mLayer;
1906         private boolean mShown;
1907         private Rect mContainingFrame;
1908         private Rect mParentFrame;
1909         private Rect mFrame;
1910         private Rect mCompatFrame;
1911         private Rect mSurfaceInsets = new Rect();
1912         private Rect mGivenContentInsets = new Rect();
1913         private Rect mCrop = new Rect();
1914         private boolean mHasCompatScale;
1915         private float mGlobalScale;
1916         private int mRequestedWidth;
1917         private int mRequestedHeight;
1918 
1919         WindowState(WindowStateProto proto) {
1920             super(proto.windowContainer);
1921             mDisplayId = proto.displayId;
1922             mStackId = proto.stackId;
1923             if (proto.attributes != null) {
1924                 mType = proto.attributes.type;
1925             }
1926             WindowStateAnimatorProto animatorProto = proto.animator;
1927             if (animatorProto != null) {
1928                 if (animatorProto.surface != null) {
1929                     WindowSurfaceControllerProto surfaceProto = animatorProto.surface;
1930                     mShown = surfaceProto.shown;
1931                     mLayer = surfaceProto.layer;
1932                 }
1933                 mCrop = extract(animatorProto.lastClipRect);
1934             }
1935             mGivenContentInsets = extract(proto.givenContentInsets);
1936             WindowFramesProto windowFramesProto = proto.windowFrames;
1937             if (windowFramesProto != null) {
1938                 mFrame = extract(windowFramesProto.frame);
1939                 mContainingFrame = extract(windowFramesProto.containingFrame);
1940                 mParentFrame = extract(windowFramesProto.parentFrame);
1941                 mCompatFrame = extract(windowFramesProto.compatFrame);
1942             }
1943             mSurfaceInsets = extract(proto.surfaceInsets);
1944             if (mName.startsWith(STARTING_WINDOW_PREFIX)) {
1945                 mWindowType = WINDOW_TYPE_STARTING;
1946                 // Existing code depends on the prefix being removed
1947                 mName = mName.substring(STARTING_WINDOW_PREFIX.length());
1948             } else if (proto.animatingExit) {
1949                 mWindowType = WINDOW_TYPE_EXITING;
1950             } else if (mName.startsWith(DEBUGGER_WINDOW_PREFIX)) {
1951                 mWindowType = WINDOW_TYPE_STARTING;
1952                 mName = mName.substring(DEBUGGER_WINDOW_PREFIX.length());
1953             } else {
1954                 mWindowType = 0;
1955             }
1956             collectDescendantsOfType(WindowState.class, this, mSubWindows);
1957             mHasCompatScale = proto.hasCompatScale;
1958             mGlobalScale = proto.globalScale;
1959             mRequestedWidth = proto.requestedWidth;
1960             mRequestedHeight = proto.requestedHeight;
1961         }
1962 
1963         boolean isStartingWindow() {
1964             return mWindowType == WINDOW_TYPE_STARTING;
1965         }
1966 
1967         boolean isExitingWindow() {
1968             return mWindowType == WINDOW_TYPE_EXITING;
1969         }
1970 
1971         boolean isDebuggerWindow() {
1972             return mWindowType == WINDOW_TYPE_DEBUGGER;
1973         }
1974 
1975         int getDisplayId() {
1976             return mDisplayId;
1977         }
1978 
1979         int getStackId() {
1980             return mStackId;
1981         }
1982 
1983         Rect getContainingFrame() {
1984             return mContainingFrame;
1985         }
1986 
1987         public Rect getFrame() {
1988             return mFrame;
1989         }
1990 
1991         Rect getSurfaceInsets() {
1992             return mSurfaceInsets;
1993         }
1994 
1995         Rect getGivenContentInsets() {
1996             return mGivenContentInsets;
1997         }
1998 
1999         Rect getParentFrame() {
2000             return mParentFrame;
2001         }
2002 
2003         public Rect getCompatFrame() {
2004             return mCompatFrame;
2005         }
2006 
2007         Rect getCrop() {
2008             return mCrop;
2009         }
2010 
2011         public boolean isSurfaceShown() {
2012             return mShown;
2013         }
2014 
2015         public int getType() {
2016             return mType;
2017         }
2018 
2019         public boolean hasCompatScale() {
2020             return mHasCompatScale;
2021         }
2022 
2023         public float getGlobalScale() {
2024             return mGlobalScale;
2025         }
2026 
2027         public int getRequestedWidth() {
2028             return mRequestedWidth;
2029         }
2030 
2031         public int getRequestedHeight() {
2032             return mRequestedHeight;
2033         }
2034 
2035         private String getWindowTypeSuffix(int windowType) {
2036             switch (windowType) {
2037                 case WINDOW_TYPE_STARTING:
2038                     return " STARTING";
2039                 case WINDOW_TYPE_EXITING:
2040                     return " EXITING";
2041                 case WINDOW_TYPE_DEBUGGER:
2042                     return " DEBUGGER";
2043                 default:
2044                     break;
2045             }
2046             return "";
2047         }
2048 
2049         @Override
2050         public String toString() {
2051             return "WindowState: {" + mAppToken + " " + mName
2052                     + getWindowTypeSuffix(mWindowType) + "}" + " type=" + mType
2053                     + " cf=" + mContainingFrame + " pf=" + mParentFrame;
2054         }
2055 
2056         public String toLongString() {
2057             return toString() + " f=" + mFrame + " crop=" + mCrop + " isSurfaceShown="
2058                     + isSurfaceShown();
2059         }
2060     }
2061 
2062     static int dpToPx(float dp, int densityDpi) {
2063         return (int) (dp * densityDpi / DENSITY_DEFAULT + 0.5f);
2064     }
2065 
2066     int defaultMinimalTaskSize(int displayId) {
2067         return dpToPx(mDefaultMinSizeOfResizableTaskDp, getDisplay(displayId).getDpi());
2068     }
2069 
2070     int defaultMinimalDisplaySizeForSplitScreen(int displayId) {
2071         return dpToPx(ActivityTaskManager.DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP,
2072                 getDisplay(displayId).getDpi());
2073     }
2074 }
2075