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