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