| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.server.am; |
| |
| import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; |
| import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; |
| import static android.server.am.ProtoExtractors.extract; |
| import static android.server.am.StateLogger.log; |
| import static android.server.am.StateLogger.logE; |
| import static android.view.Display.DEFAULT_DISPLAY; |
| |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import android.content.res.Configuration; |
| import android.graphics.Rect; |
| import android.os.ParcelFileDescriptor; |
| import android.os.SystemClock; |
| import android.support.test.InstrumentationRegistry; |
| import android.view.WindowManager; |
| import android.view.nano.DisplayInfoProto; |
| import android.view.nano.ViewProtoEnums; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| |
| import com.android.server.wm.nano.AppTransitionProto; |
| import com.android.server.wm.nano.AppWindowTokenProto; |
| import com.android.server.wm.nano.ConfigurationContainerProto; |
| import com.android.server.wm.nano.DisplayContentProto; |
| import com.android.server.wm.nano.DisplayFramesProto; |
| import com.android.server.wm.nano.IdentifierProto; |
| import com.android.server.wm.nano.PinnedStackControllerProto; |
| import com.android.server.wm.nano.StackProto; |
| import com.android.server.wm.nano.TaskProto; |
| import com.android.server.wm.nano.WindowContainerProto; |
| import com.android.server.wm.nano.WindowFramesProto; |
| import com.android.server.wm.nano.WindowManagerServiceDumpProto; |
| import com.android.server.wm.nano.WindowStateAnimatorProto; |
| import com.android.server.wm.nano.WindowStateProto; |
| import com.android.server.wm.nano.WindowSurfaceControllerProto; |
| import com.android.server.wm.nano.WindowTokenProto; |
| |
| import com.google.protobuf.nano.InvalidProtocolBufferNanoException; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.function.Predicate; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| public class WindowManagerState { |
| public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN"; |
| public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE"; |
| public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN"; |
| public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE"; |
| |
| public static final String TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN"; |
| public static final String TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE"; |
| public static final String TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN"; |
| public static final String TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE"; |
| |
| public static final String TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY"; |
| public static final String TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = |
| "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER"; |
| public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE"; |
| public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE"; |
| public static final String TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = |
| "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN"; |
| public static final String TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = |
| "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE"; |
| |
| public static final String APP_STATE_IDLE = "APP_STATE_IDLE"; |
| |
| private static final String DUMPSYS_WINDOW = "dumpsys window -a --proto"; |
| |
| private static final String STARTING_WINDOW_PREFIX = "Starting "; |
| private static final String DEBUGGER_WINDOW_PREFIX = "Waiting For Debugger: "; |
| |
| /** @see WindowManager.LayoutParams */ |
| private static final int TYPE_NAVIGATION_BAR = 2019; |
| |
| /** @see WindowManager.LayoutParams */ |
| private static final int TYPE_NAVIGATION_BAR_PANEL = 2024; |
| |
| // Windows in z-order with the top most at the front of the list. |
| private List<WindowState> mWindowStates = new ArrayList(); |
| // Stacks in z-order with the top most at the front of the list, starting with primary display. |
| private final List<WindowStack> mStacks = new ArrayList(); |
| // Stacks on all attached displays, in z-order with the top most at the front of the list. |
| private final Map<Integer, List<WindowStack>> mDisplayStacks |
| = new HashMap<>(); |
| private List<Display> mDisplays = new ArrayList(); |
| private String mFocusedWindow = null; |
| private String mFocusedApp = null; |
| private String mInputMethodWindowAppToken = null; |
| private Rect mDefaultPinnedStackBounds = new Rect(); |
| private Rect mPinnedStackMovementBounds = new Rect(); |
| private final LinkedList<String> mSysDump = new LinkedList(); |
| private int mRotation; |
| private int mLastOrientation; |
| private boolean mDisplayFrozen; |
| private boolean mIsDockedStackMinimized; |
| |
| public void computeState() { |
| // It is possible the system is in the middle of transition to the right state when we get |
| // the dump. We try a few times to get the information we need before giving up. |
| int retriesLeft = 3; |
| boolean retry = false; |
| byte[] dump = null; |
| |
| log("=============================="); |
| log(" WindowManagerState "); |
| log("=============================="); |
| do { |
| if (retry) { |
| log("***Incomplete WM state. Retrying..."); |
| // Wait half a second between retries for window manager to finish transitioning... |
| SystemClock.sleep(500); |
| } |
| |
| dump = executeShellCommand(DUMPSYS_WINDOW); |
| try { |
| parseSysDumpProto(dump); |
| } catch (InvalidProtocolBufferNanoException ex) { |
| throw new RuntimeException("Failed to parse dumpsys:\n" |
| + new String(dump, StandardCharsets.UTF_8), ex); |
| } |
| |
| retry = mWindowStates.isEmpty() || mFocusedApp == null; |
| } while (retry && retriesLeft-- > 0); |
| |
| if (mWindowStates.isEmpty()) { |
| logE("No Windows found..."); |
| } |
| if (mFocusedWindow == null) { |
| logE("No Focused Window..."); |
| } |
| if (mFocusedApp == null) { |
| logE("No Focused App..."); |
| } |
| } |
| |
| private byte[] executeShellCommand(String cmd) { |
| try { |
| ParcelFileDescriptor pfd = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .executeShellCommand(cmd); |
| byte[] buf = new byte[512]; |
| int bytesRead; |
| FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd); |
| ByteArrayOutputStream stdout = new ByteArrayOutputStream(); |
| while ((bytesRead = fis.read(buf)) != -1) { |
| stdout.write(buf, 0, bytesRead); |
| } |
| fis.close(); |
| return stdout.toByteArray(); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| |
| private void parseSysDumpProto(byte[] sysDump) throws InvalidProtocolBufferNanoException { |
| reset(); |
| WindowManagerServiceDumpProto state = WindowManagerServiceDumpProto.parseFrom(sysDump); |
| List<WindowState> allWindows = new ArrayList<>(); |
| Map<String, WindowState> windowMap = new HashMap<>(); |
| if (state.focusedWindow != null) { |
| mFocusedWindow = state.focusedWindow.title; |
| } |
| mFocusedApp = state.focusedApp; |
| for (int i = 0; i < state.rootWindowContainer.displays.length; i++) { |
| DisplayContentProto displayProto = state.rootWindowContainer.displays[i]; |
| final Display display = new Display(displayProto); |
| mDisplays.add(display); |
| allWindows.addAll(display.getWindows()); |
| List<WindowStack> stacks = new ArrayList<>(); |
| for (int j = 0; j < displayProto.stacks.length; j++) { |
| StackProto stackProto = displayProto.stacks[j]; |
| final WindowStack stack = new WindowStack(stackProto); |
| mStacks.add(stack); |
| stacks.add(stack); |
| allWindows.addAll(stack.getWindows()); |
| } |
| mDisplayStacks.put(display.mDisplayId, stacks); |
| |
| // use properties from the default display only |
| if (display.getDisplayId() == DEFAULT_DISPLAY) { |
| if (displayProto.dockedStackDividerController != null) { |
| mIsDockedStackMinimized = |
| displayProto.dockedStackDividerController.minimizedDock; |
| } |
| PinnedStackControllerProto pinnedStackProto = displayProto.pinnedStackController; |
| if (pinnedStackProto != null) { |
| mDefaultPinnedStackBounds = extract(pinnedStackProto.defaultBounds); |
| mPinnedStackMovementBounds = extract(pinnedStackProto.movementBounds); |
| } |
| } |
| } |
| for (WindowState w : allWindows) { |
| windowMap.put(w.getToken(), w); |
| } |
| for (int i = 0; i < state.rootWindowContainer.windows.length; i++) { |
| IdentifierProto identifierProto = state.rootWindowContainer.windows[i]; |
| String hash_code = Integer.toHexString(identifierProto.hashCode); |
| mWindowStates.add(windowMap.get(hash_code)); |
| } |
| if (state.inputMethodWindow != null) { |
| mInputMethodWindowAppToken = Integer.toHexString(state.inputMethodWindow.hashCode); |
| } |
| mDisplayFrozen = state.displayFrozen; |
| mRotation = state.rotation; |
| mLastOrientation = state.lastOrientation; |
| } |
| |
| static String appStateToString(int appState) { |
| switch (appState) { |
| case AppTransitionProto.APP_STATE_IDLE: |
| return "APP_STATE_IDLE"; |
| case AppTransitionProto.APP_STATE_READY: |
| return "APP_STATE_READY"; |
| case AppTransitionProto.APP_STATE_RUNNING: |
| return "APP_STATE_RUNNING"; |
| case AppTransitionProto.APP_STATE_TIMEOUT: |
| return "APP_STATE_TIMEOUT"; |
| default: |
| fail("Invalid AppTransitionState"); |
| return null; |
| } |
| } |
| |
| static String appTransitionToString(int transition) { |
| switch (transition) { |
| case ViewProtoEnums.TRANSIT_UNSET: { |
| return "TRANSIT_UNSET"; |
| } |
| case ViewProtoEnums.TRANSIT_NONE: { |
| return "TRANSIT_NONE"; |
| } |
| case ViewProtoEnums.TRANSIT_ACTIVITY_OPEN: { |
| return TRANSIT_ACTIVITY_OPEN; |
| } |
| case ViewProtoEnums.TRANSIT_ACTIVITY_CLOSE: { |
| return TRANSIT_ACTIVITY_CLOSE; |
| } |
| case ViewProtoEnums.TRANSIT_TASK_OPEN: { |
| return TRANSIT_TASK_OPEN; |
| } |
| case ViewProtoEnums.TRANSIT_TASK_CLOSE: { |
| return TRANSIT_TASK_CLOSE; |
| } |
| case ViewProtoEnums.TRANSIT_TASK_TO_FRONT: { |
| return "TRANSIT_TASK_TO_FRONT"; |
| } |
| case ViewProtoEnums.TRANSIT_TASK_TO_BACK: { |
| return "TRANSIT_TASK_TO_BACK"; |
| } |
| case ViewProtoEnums.TRANSIT_WALLPAPER_CLOSE: { |
| return TRANSIT_WALLPAPER_CLOSE; |
| } |
| case ViewProtoEnums.TRANSIT_WALLPAPER_OPEN: { |
| return TRANSIT_WALLPAPER_OPEN; |
| } |
| case ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_OPEN: { |
| return TRANSIT_WALLPAPER_INTRA_OPEN; |
| } |
| case ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_CLOSE: { |
| return TRANSIT_WALLPAPER_INTRA_CLOSE; |
| } |
| case ViewProtoEnums.TRANSIT_TASK_OPEN_BEHIND: { |
| return "TRANSIT_TASK_OPEN_BEHIND"; |
| } |
| case ViewProtoEnums.TRANSIT_ACTIVITY_RELAUNCH: { |
| return "TRANSIT_ACTIVITY_RELAUNCH"; |
| } |
| case ViewProtoEnums.TRANSIT_DOCK_TASK_FROM_RECENTS: { |
| return "TRANSIT_DOCK_TASK_FROM_RECENTS"; |
| } |
| case ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY: { |
| return TRANSIT_KEYGUARD_GOING_AWAY; |
| } |
| case ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: { |
| return TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; |
| } |
| case ViewProtoEnums.TRANSIT_KEYGUARD_OCCLUDE: { |
| return TRANSIT_KEYGUARD_OCCLUDE; |
| } |
| case ViewProtoEnums.TRANSIT_KEYGUARD_UNOCCLUDE: { |
| return TRANSIT_KEYGUARD_UNOCCLUDE; |
| } |
| case ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: { |
| return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN; |
| } |
| case ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: { |
| return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE; |
| } |
| case ViewProtoEnums.TRANSIT_CRASHING_ACTIVITY_CLOSE: { |
| return "TRANSIT_CRASHING_ACTIVITY_CLOSE"; |
| } |
| default: { |
| fail("Invalid lastUsedAppTransition"); |
| return null; |
| } |
| } |
| } |
| |
| List<WindowState> getMatchingWindowType(int type) { |
| return getMatchingWindows(ws -> type == ws.mType).collect(Collectors.toList()); |
| } |
| |
| List<String> getMatchingWindowTokens(final String windowName) { |
| return getMatchingWindows(ws -> windowName.equals(ws.getName())) |
| .map(WindowState::getToken) |
| .collect(Collectors.toList()); |
| } |
| |
| List<WindowState> getAllNavigationBarStates() { |
| return getMatchingWindows(WindowManagerState::isValidNavBarType) |
| .collect(Collectors.toList()); |
| } |
| |
| WindowState getAndAssertSingleNavBarWindowOnDisplay(int displayId) { |
| List<WindowState> navWindow = getMatchingWindows(ws -> |
| isValidNavBarType(ws) && ws.getDisplayId() == displayId) |
| .collect(Collectors.toList()); |
| |
| // We may need some time to wait for nav bar showing. |
| // It's Ok to get 0 nav bar here. |
| assertTrue("There should be at most one navigation bar on a display", |
| navWindow.size() <= 1); |
| |
| return navWindow.isEmpty() ? null : navWindow.get(0); |
| } |
| |
| private static boolean isValidNavBarType(WindowState navState) { |
| return TYPE_NAVIGATION_BAR == navState.getType(); |
| } |
| |
| public List<WindowState> getMatchingVisibleWindowState(final String windowName) { |
| return getMatchingWindows(ws -> ws.isShown() && windowName.equals(ws.getName())) |
| .collect(Collectors.toList()); |
| } |
| |
| List<WindowState> getExitingWindows() { |
| return getMatchingWindows(WindowState::isExitingWindow) |
| .collect(Collectors.toList()); |
| } |
| |
| private Stream<WindowState> getMatchingWindows(Predicate<WindowState> condition) { |
| return mWindowStates.stream().filter(condition); |
| } |
| |
| @Nullable |
| public WindowState getWindowByPackageName(String packageName, int windowType) { |
| final List<WindowState> windowList = getWindowsByPackageName(packageName, windowType); |
| return windowList.isEmpty() ? null : windowList.get(0); |
| } |
| |
| public List<WindowState> getWindowsByPackageName(String packageName, int... restrictToTypes) { |
| return getMatchingWindows(ws -> |
| (ws.getName().equals(packageName) || ws.getName().startsWith(packageName + "/")) |
| && Arrays.stream(restrictToTypes).anyMatch(type -> type == ws.getType())) |
| .collect(Collectors.toList()); |
| } |
| |
| WindowState getWindowStateForAppToken(String appToken) { |
| return getMatchingWindows(ws -> ws.getToken().equals(appToken)) |
| .findFirst() |
| .orElse(null); |
| } |
| |
| Display getDisplay(int displayId) { |
| for (Display display : mDisplays) { |
| if (displayId == display.getDisplayId()) { |
| return display; |
| } |
| } |
| return null; |
| } |
| |
| List<Display> getDisplays() { |
| return mDisplays; |
| } |
| |
| String getFrontWindow() { |
| if (mWindowStates == null || mWindowStates.isEmpty()) { |
| return null; |
| } |
| return mWindowStates.get(0).getName(); |
| } |
| |
| public String getFocusedWindow() { |
| return mFocusedWindow; |
| } |
| |
| public String getFocusedApp() { |
| return mFocusedApp; |
| } |
| |
| String getDefaultDisplayLastTransition() { |
| return getDisplay(DEFAULT_DISPLAY).getLastTransition(); |
| } |
| |
| String getDefaultDisplayAppTransitionState() { |
| return getDisplay(DEFAULT_DISPLAY).getAppTransitionState(); |
| } |
| |
| int getFrontStackId(int displayId) { |
| return mDisplayStacks.get(displayId).get(0).mStackId; |
| } |
| |
| int getFrontStackActivityType(int displayId) { |
| return mDisplayStacks.get(displayId).get(0).getActivityType(); |
| } |
| |
| public int getRotation() { |
| return mRotation; |
| } |
| |
| int getLastOrientation() { |
| return mLastOrientation; |
| } |
| |
| boolean containsStack(int stackId) { |
| for (WindowStack stack : mStacks) { |
| if (stackId == stack.mStackId) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| boolean containsStack(int windowingMode, int activityType) { |
| for (WindowStack stack : mStacks) { |
| if (activityType != ACTIVITY_TYPE_UNDEFINED |
| && activityType != stack.getActivityType()) { |
| continue; |
| } |
| if (windowingMode != WINDOWING_MODE_UNDEFINED |
| && windowingMode != stack.getWindowingMode()) { |
| continue; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Check if there exists a window record with matching windowName. |
| */ |
| public boolean containsWindow(String windowName) { |
| for (WindowState window : mWindowStates) { |
| if (window.getName().equals(windowName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Check if at least one window which matches provided window name is visible. |
| */ |
| boolean isWindowVisible(String windowName) { |
| for (WindowState window : mWindowStates) { |
| if (window.getName().equals(windowName)) { |
| if (window.isShown()) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| boolean allWindowsVisible(String windowName) { |
| boolean allVisible = false; |
| for (WindowState window : mWindowStates) { |
| if (window.getName().equals(windowName)) { |
| if (!window.isShown()) { |
| log("[VISIBLE] not visible" + windowName); |
| return false; |
| } |
| log("[VISIBLE] visible" + windowName); |
| allVisible = true; |
| } |
| } |
| return allVisible; |
| } |
| |
| WindowStack getStack(int stackId) { |
| for (WindowStack stack : mStacks) { |
| if (stackId == stack.mStackId) { |
| return stack; |
| } |
| } |
| return null; |
| } |
| |
| WindowStack getStandardStackByWindowingMode(int windowingMode) { |
| for (WindowStack stack : mStacks) { |
| if (stack.getActivityType() != ACTIVITY_TYPE_STANDARD) { |
| continue; |
| } |
| if (stack.getWindowingMode() == windowingMode) { |
| return stack; |
| } |
| } |
| return null; |
| } |
| |
| /** Get the stack position on its display. */ |
| int getStackIndexByActivityType(int activityType) { |
| for (Integer displayId : mDisplayStacks.keySet()) { |
| List<WindowStack> stacks = mDisplayStacks.get(displayId); |
| for (int i = 0; i < stacks.size(); i++) { |
| if (activityType == stacks.get(i).getActivityType()) { |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| WindowState getInputMethodWindowState() { |
| return getWindowStateForAppToken(mInputMethodWindowAppToken); |
| } |
| |
| Rect getStableBounds() { |
| return getDisplay(DEFAULT_DISPLAY).mStableBounds; |
| } |
| |
| Rect getDefaultPinnedStackBounds() { |
| return new Rect(mDefaultPinnedStackBounds); |
| } |
| |
| Rect getPinnedStackMovementBounds() { |
| return new Rect(mPinnedStackMovementBounds); |
| } |
| |
| WindowState findFirstWindowWithType(int type) { |
| for (WindowState window : mWindowStates) { |
| if (window.getType() == type) { |
| return window; |
| } |
| } |
| return null; |
| } |
| |
| public boolean isDisplayFrozen() { |
| return mDisplayFrozen; |
| } |
| |
| public boolean isDockedStackMinimized() { |
| return mIsDockedStackMinimized; |
| } |
| |
| public int getZOrder(WindowState w) { |
| return mWindowStates.size() - mWindowStates.indexOf(w); |
| } |
| |
| private void reset() { |
| mSysDump.clear(); |
| mStacks.clear(); |
| mDisplays.clear(); |
| mWindowStates.clear(); |
| mDisplayStacks.clear(); |
| mFocusedWindow = null; |
| mFocusedApp = null; |
| mInputMethodWindowAppToken = null; |
| mIsDockedStackMinimized = false; |
| mDefaultPinnedStackBounds.setEmpty(); |
| mPinnedStackMovementBounds.setEmpty(); |
| mRotation = 0; |
| mLastOrientation = 0; |
| mDisplayFrozen = false; |
| } |
| |
| static class WindowStack extends WindowContainer { |
| |
| int mStackId; |
| ArrayList<WindowTask> mTasks = new ArrayList<>(); |
| boolean mWindowAnimationBackgroundSurfaceShowing; |
| boolean mAnimatingBounds; |
| |
| WindowStack(StackProto proto) { |
| super(proto.windowContainer); |
| mStackId = proto.id; |
| mFullscreen = proto.fillsParent; |
| mBounds = extract(proto.bounds); |
| for (int i = 0; i < proto.tasks.length; i++) { |
| TaskProto taskProto = proto.tasks[i]; |
| WindowTask task = new WindowTask(taskProto); |
| mTasks.add(task); |
| mSubWindows.addAll(task.getWindows()); |
| } |
| mWindowAnimationBackgroundSurfaceShowing = proto.animationBackgroundSurfaceIsDimming; |
| mAnimatingBounds = proto.animatingBounds; |
| } |
| |
| WindowTask getTask(int taskId) { |
| for (WindowTask task : mTasks) { |
| if (taskId == task.mTaskId) { |
| return task; |
| } |
| } |
| return null; |
| } |
| |
| boolean isWindowAnimationBackgroundSurfaceShowing() { |
| return mWindowAnimationBackgroundSurfaceShowing; |
| } |
| } |
| |
| static class WindowTask extends WindowContainer { |
| |
| int mTaskId; |
| List<String> mAppTokens = new ArrayList<>(); |
| private int mSurfaceWidth; |
| private int mSurfaceHeight; |
| |
| WindowTask(TaskProto proto) { |
| super(proto.windowContainer); |
| mTaskId = proto.id; |
| mFullscreen = proto.fillsParent; |
| mBounds = extract(proto.bounds); |
| for (int i = 0; i < proto.appWindowTokens.length; i++) { |
| AppWindowTokenProto appWindowTokenProto = proto.appWindowTokens[i]; |
| mAppTokens.add(appWindowTokenProto.name); |
| WindowTokenProto windowTokenProto = appWindowTokenProto.windowToken; |
| for (int j = 0; j < windowTokenProto.windows.length; j++) { |
| WindowStateProto windowProto = windowTokenProto.windows[j]; |
| WindowState window = new WindowState(windowProto); |
| mSubWindows.add(window); |
| mSubWindows.addAll(window.getWindows()); |
| } |
| } |
| mSurfaceWidth = proto.surfaceWidth; |
| mSurfaceHeight = proto.surfaceHeight; |
| } |
| |
| int getSurfaceWidth() { |
| return mSurfaceWidth; |
| } |
| |
| int getSurfaceHeight() { |
| return mSurfaceHeight; |
| } |
| } |
| |
| static class ConfigurationContainer { |
| final Configuration mOverrideConfiguration = new Configuration(); |
| final Configuration mFullConfiguration = new Configuration(); |
| final Configuration mMergedOverrideConfiguration = new Configuration(); |
| |
| ConfigurationContainer(ConfigurationContainerProto proto) { |
| if (proto == null) { |
| return; |
| } |
| mOverrideConfiguration.setTo(extract(proto.overrideConfiguration)); |
| mFullConfiguration.setTo(extract(proto.fullConfiguration)); |
| mMergedOverrideConfiguration.setTo(extract(proto.mergedOverrideConfiguration)); |
| } |
| |
| int getWindowingMode() { |
| if (mFullConfiguration == null) { |
| return WINDOWING_MODE_UNDEFINED; |
| } |
| return mFullConfiguration.windowConfiguration.getWindowingMode(); |
| } |
| |
| int getActivityType() { |
| if (mFullConfiguration == null) { |
| return ACTIVITY_TYPE_UNDEFINED; |
| } |
| return mFullConfiguration.windowConfiguration.getActivityType(); |
| } |
| } |
| |
| static abstract class WindowContainer extends ConfigurationContainer { |
| |
| protected boolean mFullscreen; |
| protected Rect mBounds; |
| protected int mOrientation; |
| protected List<WindowState> mSubWindows = new ArrayList<>(); |
| |
| WindowContainer(WindowContainerProto proto) { |
| super(proto.configurationContainer); |
| mOrientation = proto.orientation; |
| } |
| |
| Rect getBounds() { |
| return mBounds; |
| } |
| |
| boolean isFullscreen() { |
| return mFullscreen; |
| } |
| |
| List<WindowState> getWindows() { |
| return mSubWindows; |
| } |
| } |
| |
| static class Display extends WindowContainer { |
| |
| private final int mDisplayId; |
| private Rect mDisplayRect = new Rect(); |
| private Rect mAppRect = new Rect(); |
| private int mDpi; |
| private Rect mStableBounds; |
| private String mName; |
| private int mSurfaceSize; |
| private String mFocusedApp; |
| private String mLastTransition; |
| private String mAppTransitionState; |
| |
| public Display(DisplayContentProto proto) { |
| super(proto.windowContainer); |
| mDisplayId = proto.id; |
| for (int i = 0; i < proto.aboveAppWindows.length; i++) { |
| addWindowsFromTokenProto(proto.aboveAppWindows[i]); |
| } |
| for (int i = 0; i < proto.belowAppWindows.length; i++) { |
| addWindowsFromTokenProto(proto.belowAppWindows[i]); |
| } |
| for (int i = 0; i < proto.imeWindows.length; i++) { |
| addWindowsFromTokenProto(proto.imeWindows[i]); |
| } |
| mDpi = proto.dpi; |
| DisplayInfoProto infoProto = proto.displayInfo; |
| if (infoProto != null) { |
| mDisplayRect.set(0, 0, infoProto.logicalWidth, infoProto.logicalHeight); |
| mAppRect.set(0, 0, infoProto.appWidth, infoProto.appHeight); |
| mName = infoProto.name; |
| } |
| final DisplayFramesProto displayFramesProto = proto.displayFrames; |
| if (displayFramesProto != null) { |
| mStableBounds = extract(displayFramesProto.stableBounds); |
| } |
| mSurfaceSize = proto.surfaceSize; |
| mFocusedApp = proto.focusedApp; |
| |
| final AppTransitionProto appTransitionProto = proto.appTransition; |
| int appState = 0; |
| int lastTransition = 0; |
| if (appTransitionProto != null) { |
| appState = appTransitionProto.appTransitionState; |
| lastTransition = appTransitionProto.lastUsedAppTransition; |
| } |
| mAppTransitionState = appStateToString(appState); |
| mLastTransition = appTransitionToString(lastTransition); |
| } |
| |
| private void addWindowsFromTokenProto(WindowTokenProto proto) { |
| for (int j = 0; j < proto.windows.length; j++) { |
| WindowStateProto windowProto = proto.windows[j]; |
| WindowState childWindow = new WindowState(windowProto); |
| mSubWindows.add(childWindow); |
| mSubWindows.addAll(childWindow.getWindows()); |
| } |
| } |
| |
| int getDisplayId() { |
| return mDisplayId; |
| } |
| |
| int getDpi() { |
| return mDpi; |
| } |
| |
| Rect getDisplayRect() { |
| return mDisplayRect; |
| } |
| |
| Rect getAppRect() { |
| return mAppRect; |
| } |
| |
| String getName() { |
| return mName; |
| } |
| |
| int getSurfaceSize() { |
| return mSurfaceSize; |
| } |
| |
| String getFocusedApp() { |
| return mFocusedApp; |
| } |
| |
| String getLastTransition() { return mLastTransition; } |
| |
| String getAppTransitionState() { return mAppTransitionState; } |
| |
| @Override |
| public String toString() { |
| return "Display #" + mDisplayId + ": name=" + mName + " mDisplayRect=" + mDisplayRect |
| + " mAppRect=" + mAppRect; |
| } |
| } |
| |
| public static class WindowState extends WindowContainer { |
| |
| private static final int WINDOW_TYPE_NORMAL = 0; |
| private static final int WINDOW_TYPE_STARTING = 1; |
| private static final int WINDOW_TYPE_EXITING = 2; |
| private static final int WINDOW_TYPE_DEBUGGER = 3; |
| |
| private String mName; |
| private final String mAppToken; |
| private final int mWindowType; |
| private int mType = 0; |
| private int mDisplayId; |
| private int mStackId; |
| private int mLayer; |
| private boolean mShown; |
| private Rect mContainingFrame; |
| private Rect mParentFrame; |
| private Rect mContentFrame; |
| private Rect mFrame; |
| private Rect mSurfaceInsets = new Rect(); |
| private Rect mContentInsets = new Rect(); |
| private Rect mGivenContentInsets = new Rect(); |
| private Rect mCrop = new Rect(); |
| |
| WindowState(WindowStateProto proto) { |
| super(proto.windowContainer); |
| IdentifierProto identifierProto = proto.identifier; |
| mName = identifierProto.title; |
| mAppToken = Integer.toHexString(identifierProto.hashCode); |
| mDisplayId = proto.displayId; |
| mStackId = proto.stackId; |
| if (proto.attributes != null) { |
| mType = proto.attributes.type; |
| } |
| WindowStateAnimatorProto animatorProto = proto.animator; |
| if (animatorProto != null) { |
| if (animatorProto.surface != null) { |
| WindowSurfaceControllerProto surfaceProto = animatorProto.surface; |
| mShown = surfaceProto.shown; |
| mLayer = surfaceProto.layer; |
| } |
| mCrop = extract(animatorProto.lastClipRect); |
| } |
| mGivenContentInsets = extract(proto.givenContentInsets); |
| WindowFramesProto windowFramesProto = proto.windowFrames; |
| if (windowFramesProto != null) { |
| mFrame = extract(windowFramesProto.frame); |
| mContainingFrame = extract(windowFramesProto.containingFrame); |
| mParentFrame = extract(windowFramesProto.parentFrame); |
| mContentFrame = extract(windowFramesProto.contentFrame); |
| mContentInsets = extract(windowFramesProto.contentInsets); |
| } |
| mSurfaceInsets = extract(proto.surfaceInsets); |
| if (mName.startsWith(STARTING_WINDOW_PREFIX)) { |
| mWindowType = WINDOW_TYPE_STARTING; |
| // Existing code depends on the prefix being removed |
| mName = mName.substring(STARTING_WINDOW_PREFIX.length()); |
| } else if (proto.animatingExit) { |
| mWindowType = WINDOW_TYPE_EXITING; |
| } else if (mName.startsWith(DEBUGGER_WINDOW_PREFIX)) { |
| mWindowType = WINDOW_TYPE_STARTING; |
| mName = mName.substring(DEBUGGER_WINDOW_PREFIX.length()); |
| } else { |
| mWindowType = 0; |
| } |
| for (int i = 0; i < proto.childWindows.length; i++) { |
| WindowStateProto childProto = proto.childWindows[i]; |
| WindowState childWindow = new WindowState(childProto); |
| mSubWindows.add(childWindow); |
| mSubWindows.addAll(childWindow.getWindows()); |
| } |
| } |
| |
| @NonNull |
| public String getName() { |
| return mName; |
| } |
| |
| String getToken() { |
| return mAppToken; |
| } |
| |
| boolean isStartingWindow() { |
| return mWindowType == WINDOW_TYPE_STARTING; |
| } |
| |
| boolean isExitingWindow() { |
| return mWindowType == WINDOW_TYPE_EXITING; |
| } |
| |
| boolean isDebuggerWindow() { |
| return mWindowType == WINDOW_TYPE_DEBUGGER; |
| } |
| |
| int getDisplayId() { |
| return mDisplayId; |
| } |
| |
| int getStackId() { |
| return mStackId; |
| } |
| |
| Rect getContainingFrame() { |
| return mContainingFrame; |
| } |
| |
| public Rect getFrame() { |
| return mFrame; |
| } |
| |
| Rect getSurfaceInsets() { |
| return mSurfaceInsets; |
| } |
| |
| Rect getContentInsets() { |
| return mContentInsets; |
| } |
| |
| Rect getGivenContentInsets() { |
| return mGivenContentInsets; |
| } |
| |
| public Rect getContentFrame() { |
| return mContentFrame; |
| } |
| |
| Rect getParentFrame() { |
| return mParentFrame; |
| } |
| |
| Rect getCrop() { |
| return mCrop; |
| } |
| |
| public boolean isShown() { |
| return mShown; |
| } |
| |
| public int getType() { |
| return mType; |
| } |
| |
| private String getWindowTypeSuffix(int windowType) { |
| switch (windowType) { |
| case WINDOW_TYPE_STARTING: |
| return " STARTING"; |
| case WINDOW_TYPE_EXITING: |
| return " EXITING"; |
| case WINDOW_TYPE_DEBUGGER: |
| return " DEBUGGER"; |
| default: |
| break; |
| } |
| return ""; |
| } |
| |
| @Override |
| public String toString() { |
| return "WindowState: {" + mAppToken + " " + mName |
| + getWindowTypeSuffix(mWindowType) + "}" + " type=" + mType |
| + " cf=" + mContainingFrame + " pf=" + mParentFrame; |
| } |
| } |
| } |