Loading services/core/java/com/android/server/wm/ActivityRecord.java +5 −1 Original line number Diff line number Diff line Loading @@ -1721,7 +1721,7 @@ final class ActivityRecord extends WindowToken { } mAppCompatController.getLetterboxPolicy().onMovedToDisplay(mDisplayContent.getDisplayId()); mAppCompatController.getDisplayCompatModePolicy().onMovedToDisplay(); mAppCompatController.getDisplayCompatModePolicy().onMovedToDisplay(prevDc, dc); } void layoutLetterboxIfNeeded(WindowState winHint) { Loading Loading @@ -8590,6 +8590,10 @@ final class ActivityRecord extends WindowToken { configChanged |= CONFIG_UI_MODE; } // Some apps relaunch unexpectedly with display move and crash. configChanged |= mAppCompatController.getDisplayCompatModePolicy() .getDisplayCompatModeConfigMask(); return (changes & (~configChanged)) != 0; } Loading services/core/java/com/android/server/wm/AppCompatController.java +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ class AppCompatController { mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord, mAppCompatOverrides); mSandboxingPolicy = new AppCompatSandboxingPolicy(activityRecord); mDisplayCompatModePolicy = new AppCompatDisplayCompatModePolicy(); mDisplayCompatModePolicy = new AppCompatDisplayCompatModePolicy(activityRecord); } @NonNull Loading services/core/java/com/android/server/wm/AppCompatDisplayCompatModePolicy.java +89 −5 Original line number Diff line number Diff line Loading @@ -16,24 +16,108 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.CONFIG_COLOR_MODE; import static android.content.pm.ActivityInfo.CONFIG_DENSITY; import static android.content.pm.ActivityInfo.CONFIG_TOUCHSCREEN; import static android.view.Display.TYPE_INTERNAL; import android.annotation.NonNull; import android.content.pm.ApplicationInfo; import com.android.window.flags.Flags; /** * Encapsulate app-compat logic for multi-display environments. * * <p>The primary feature is "display compat mode", which suppresses automatic activity restart * caused by display-specific config changes to prevent unexpected crashes. * The current conditions of an app being in display compat mode are: * <ul> * <li>The app is a game. * <li>The app doesn't support all of {@link DISPLAY_COMPAT_MODE_CONFIG_MASK}. * <li>The app has moved to a different display but not restarted yet. * </ul> * * <p>Display compat mode comes with restart handle menu, with which the app process gets recreated, * and all the config changes get reloaded by the app, at the timing the user wants to do so with * the risk of losing the current state of the app. */ class AppCompatDisplayCompatModePolicy { private boolean mIsRestartMenuEnabledForDisplayMove; private static final int DISPLAY_COMPAT_MODE_CONFIG_MASK = CONFIG_DENSITY | CONFIG_TOUCHSCREEN | CONFIG_COLOR_MODE; @NonNull private final ActivityRecord mActivityRecord; private boolean mDisplayChangedWithoutRestart; AppCompatDisplayCompatModePolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; } /** * Returns whether the restart menu is enabled for display move. Currently it only gets shown * when an app is in display compat mode. * * @return {@code true} if the restart menu should be enabled for display move. */ boolean isRestartMenuEnabledForDisplayMove() { return Flags.enableRestartMenuForConnectedDisplays() && mIsRestartMenuEnabledForDisplayMove; // Restart menu is only available to apps in display compat mode. return Flags.enableRestartMenuForConnectedDisplays() && mDisplayChangedWithoutRestart && getDisplayCompatModeConfigMask() != 0; } void onMovedToDisplay() { mIsRestartMenuEnabledForDisplayMove = true; /** * Called when the activity is moved to a different display. * * @param previousDisplay The display the app was on before this display transition. * @param newDisplay The new display the app got moved onto. */ void onMovedToDisplay(@NonNull DisplayContent previousDisplay, @NonNull DisplayContent newDisplay) { if (previousDisplay.getDisplayInfo().type == TYPE_INTERNAL && newDisplay.getDisplayInfo().type == TYPE_INTERNAL) { // A transition between internal displays (fold<->unfold on foldable) is not considered // display move here for now because they generally have many configurations in common, // thus are less likely to cause compat issues. return; } mDisplayChangedWithoutRestart = true; } /** * Called when the activity's process is restarted. */ void onProcessRestarted() { mIsRestartMenuEnabledForDisplayMove = false; mDisplayChangedWithoutRestart = false; } /** * Returns the mask of the config changes that should not trigger activity restart with display * move for app-compat reasons. * * @return the mask of the config changes that should not trigger activity restart or 0 if * display compat mode is not enabled for the activity. */ int getDisplayCompatModeConfigMask() { if (!Flags.enableDisplayCompatMode()) return 0; if (mActivityRecord.info.applicationInfo.category != ApplicationInfo.CATEGORY_GAME) { // A large majority of apps that crash with display move are games. Apply this compat // treatment only to games to minimize risk. return 0; } if (!mDisplayChangedWithoutRestart) { // Enable display compat mode when display move is involved. return 0; } // If a specific config change is supported by the activity, it's exempted from this compat // treatment. This way, apps can opt out from display compat mode by handling all the config // changes that happen with display move by themselves. final int supportedConfigChanged = mActivityRecord.info.getRealConfigChanged(); return DISPLAY_COMPAT_MODE_CONFIG_MASK & (~supportedConfigChanged); } } services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java +54 −1 Original line number Diff line number Diff line Loading @@ -22,13 +22,18 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ApplicationInfo.CATEGORY_GAME; import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.WindowConfiguration.WindowingMode; Loading @@ -37,6 +42,9 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager.UserMinAspectRatio; import android.content.res.Configuration; import android.graphics.Rect; import android.view.Display; import android.view.DisplayInfo; import android.view.InputDevice; import android.view.Surface; import androidx.annotation.CallSuper; Loading Loading @@ -188,6 +196,7 @@ class AppCompatActivityRobot { void moveTaskToSecondaryDisplay() { mTaskStack.top().reparent(mSecondaryDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */); mActivityStack.top().ensureActivityConfiguration(); } void setTaskDisplayAreaWindowingMode(@WindowingMode int windowingMode) { Loading Loading @@ -313,6 +322,21 @@ class AppCompatActivityRobot { } } void setTopActivityGame(boolean isGame) { mActivityStack.top().info.applicationInfo.category = isGame ? CATEGORY_GAME : CATEGORY_UNDEFINED; } void setTopActivityResumed() { mActivityStack.top().setVisible(true); mActivityStack.top().setVisibleRequested(true); mActivityStack.top().setState(RESUMED, "setTopActivityResumed"); } void setTopActivityConfigChanges(int supportedConfigChanges) { mActivityStack.top().info.configChanges = supportedConfigChanges; } void setFixedRotationTransformDisplayBounds(@Nullable Rect bounds) { doReturn(bounds).when(mActivityStack.top()).getFixedRotationTransformDisplayBounds(); } Loading @@ -331,9 +355,33 @@ class AppCompatActivityRobot { onPostDisplayContentCreation(mDisplayContent); } /** * Creates a secondary display. Its density, color mode, and touchscreen are intentionally set * different from those of the default display to emulate common physical environments. */ void createSecondaryDisplay() { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayContent.getDisplayInfo()); displayInfo.type = Display.TYPE_EXTERNAL; final int[] hdrTypesWithDv = new int[] {1, 2, 3, 4}; displayInfo.hdrCapabilities = new Display.HdrCapabilities(hdrTypesWithDv, 0, 0, 0); doReturn(true).when(mAtm.mWindowManager).hasHdrSupport(); mSecondaryDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayWidth, mDisplayHeight).build(); new TestDisplayContent.Builder(mAtm, displayInfo).build(); mSecondaryDisplayContent.setForcedDensity(123, mAtm.mWindowManager.mCurrentUserId); final InputDevice device = new InputDevice.Builder() .setAssociatedDisplayId(mSecondaryDisplayContent.mDisplayId) .setSources(InputDevice.SOURCE_TOUCHSCREEN) .build(); final InputDevice[] devices = {device}; doReturn(true).when(mSecondaryDisplayContent.mWmService.mInputManager) .canDispatchToDisplay(device.getId(), mSecondaryDisplayContent.mDisplayId); doReturn(devices).when(mSecondaryDisplayContent.mWmService.mInputManager).getInputDevices(); mAtm.mWindowManager.mIsTouchDevice = true; mAtm.mWindowManager.displayReady(); onPostDisplayContentCreation(mSecondaryDisplayContent); } Loading Loading @@ -421,6 +469,11 @@ class AppCompatActivityRobot { Assert.assertNull(getter.apply(mActivityStack.top())); } void checkTopActivityRelaunched(boolean relaunched) { verify(mActivityStack.top(), times(relaunched ? 1 : 0)).relaunchActivityLocked(anyBoolean(), anyInt()); } void checkTopActivityRecomputedConfiguration() { verify(mActivityStack.top()).recomputeConfiguration(); } Loading services/tests/wmtests/src/com/android/server/wm/AppCompatDisplayCompatTests.java +30 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.CONFIG_COLOR_MODE; import static android.content.pm.ActivityInfo.CONFIG_DENSITY; import static android.content.pm.ActivityInfo.CONFIG_RESOURCES_UNUSED; import static android.content.pm.ActivityInfo.CONFIG_TOUCHSCREEN; import static com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_COMPAT_MODE; import static com.android.window.flags.Flags.FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS; import static org.junit.Assert.assertEquals; Loading @@ -42,15 +48,22 @@ import java.util.function.Consumer; @RunWith(WindowTestRunner.class) public class AppCompatDisplayCompatTests extends WindowTestsBase { @EnableFlags(FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS) private static final int CONFIG_MASK_FOR_DISPLAY_MOVE = ~(CONFIG_DENSITY | CONFIG_TOUCHSCREEN | CONFIG_COLOR_MODE | CONFIG_RESOURCES_UNUSED); @EnableFlags({FLAG_ENABLE_DISPLAY_COMPAT_MODE, FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS}) @Test public void testRestartMenuVisibility() { public void testDisplayCompatMode_gameDoesNotRestartWithDisplayMove() { runTestScenario((robot) -> { robot.activity().createSecondaryDisplay(); robot.activity().createActivityWithComponent(); robot.activity().setTopActivityGame(true); robot.activity().setTopActivityResumed(); robot.activity().setTopActivityConfigChanges(CONFIG_MASK_FOR_DISPLAY_MOVE); robot.checkRestartMenuVisibility(false); robot.activity().moveTaskToSecondaryDisplay(); robot.activity().checkTopActivityRelaunched(false); robot.checkRestartMenuVisibility(true); robot.activity().applyToTopActivity(ActivityRecord::restartProcessIfVisible); Loading @@ -58,6 +71,21 @@ public class AppCompatDisplayCompatTests extends WindowTestsBase { }); } @Test public void testDisplayCompatMode_nonGameRestartsWithDisplayMove() { runTestScenario((robot) -> { robot.activity().createSecondaryDisplay(); robot.activity().createActivityWithComponent(); robot.activity().setTopActivityResumed(); robot.activity().setTopActivityConfigChanges(CONFIG_MASK_FOR_DISPLAY_MOVE); robot.checkRestartMenuVisibility(false); robot.activity().moveTaskToSecondaryDisplay(); robot.activity().checkTopActivityRelaunched(true); robot.checkRestartMenuVisibility(false); }); } void runTestScenario(@NonNull Consumer<DisplayCompatRobotTest> consumer) { final DisplayCompatRobotTest robot = new DisplayCompatRobotTest(mWm, mAtm, mSupervisor); consumer.accept(robot); Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +5 −1 Original line number Diff line number Diff line Loading @@ -1721,7 +1721,7 @@ final class ActivityRecord extends WindowToken { } mAppCompatController.getLetterboxPolicy().onMovedToDisplay(mDisplayContent.getDisplayId()); mAppCompatController.getDisplayCompatModePolicy().onMovedToDisplay(); mAppCompatController.getDisplayCompatModePolicy().onMovedToDisplay(prevDc, dc); } void layoutLetterboxIfNeeded(WindowState winHint) { Loading Loading @@ -8590,6 +8590,10 @@ final class ActivityRecord extends WindowToken { configChanged |= CONFIG_UI_MODE; } // Some apps relaunch unexpectedly with display move and crash. configChanged |= mAppCompatController.getDisplayCompatModePolicy() .getDisplayCompatModeConfigMask(); return (changes & (~configChanged)) != 0; } Loading
services/core/java/com/android/server/wm/AppCompatController.java +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ class AppCompatController { mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord, mAppCompatOverrides); mSandboxingPolicy = new AppCompatSandboxingPolicy(activityRecord); mDisplayCompatModePolicy = new AppCompatDisplayCompatModePolicy(); mDisplayCompatModePolicy = new AppCompatDisplayCompatModePolicy(activityRecord); } @NonNull Loading
services/core/java/com/android/server/wm/AppCompatDisplayCompatModePolicy.java +89 −5 Original line number Diff line number Diff line Loading @@ -16,24 +16,108 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.CONFIG_COLOR_MODE; import static android.content.pm.ActivityInfo.CONFIG_DENSITY; import static android.content.pm.ActivityInfo.CONFIG_TOUCHSCREEN; import static android.view.Display.TYPE_INTERNAL; import android.annotation.NonNull; import android.content.pm.ApplicationInfo; import com.android.window.flags.Flags; /** * Encapsulate app-compat logic for multi-display environments. * * <p>The primary feature is "display compat mode", which suppresses automatic activity restart * caused by display-specific config changes to prevent unexpected crashes. * The current conditions of an app being in display compat mode are: * <ul> * <li>The app is a game. * <li>The app doesn't support all of {@link DISPLAY_COMPAT_MODE_CONFIG_MASK}. * <li>The app has moved to a different display but not restarted yet. * </ul> * * <p>Display compat mode comes with restart handle menu, with which the app process gets recreated, * and all the config changes get reloaded by the app, at the timing the user wants to do so with * the risk of losing the current state of the app. */ class AppCompatDisplayCompatModePolicy { private boolean mIsRestartMenuEnabledForDisplayMove; private static final int DISPLAY_COMPAT_MODE_CONFIG_MASK = CONFIG_DENSITY | CONFIG_TOUCHSCREEN | CONFIG_COLOR_MODE; @NonNull private final ActivityRecord mActivityRecord; private boolean mDisplayChangedWithoutRestart; AppCompatDisplayCompatModePolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; } /** * Returns whether the restart menu is enabled for display move. Currently it only gets shown * when an app is in display compat mode. * * @return {@code true} if the restart menu should be enabled for display move. */ boolean isRestartMenuEnabledForDisplayMove() { return Flags.enableRestartMenuForConnectedDisplays() && mIsRestartMenuEnabledForDisplayMove; // Restart menu is only available to apps in display compat mode. return Flags.enableRestartMenuForConnectedDisplays() && mDisplayChangedWithoutRestart && getDisplayCompatModeConfigMask() != 0; } void onMovedToDisplay() { mIsRestartMenuEnabledForDisplayMove = true; /** * Called when the activity is moved to a different display. * * @param previousDisplay The display the app was on before this display transition. * @param newDisplay The new display the app got moved onto. */ void onMovedToDisplay(@NonNull DisplayContent previousDisplay, @NonNull DisplayContent newDisplay) { if (previousDisplay.getDisplayInfo().type == TYPE_INTERNAL && newDisplay.getDisplayInfo().type == TYPE_INTERNAL) { // A transition between internal displays (fold<->unfold on foldable) is not considered // display move here for now because they generally have many configurations in common, // thus are less likely to cause compat issues. return; } mDisplayChangedWithoutRestart = true; } /** * Called when the activity's process is restarted. */ void onProcessRestarted() { mIsRestartMenuEnabledForDisplayMove = false; mDisplayChangedWithoutRestart = false; } /** * Returns the mask of the config changes that should not trigger activity restart with display * move for app-compat reasons. * * @return the mask of the config changes that should not trigger activity restart or 0 if * display compat mode is not enabled for the activity. */ int getDisplayCompatModeConfigMask() { if (!Flags.enableDisplayCompatMode()) return 0; if (mActivityRecord.info.applicationInfo.category != ApplicationInfo.CATEGORY_GAME) { // A large majority of apps that crash with display move are games. Apply this compat // treatment only to games to minimize risk. return 0; } if (!mDisplayChangedWithoutRestart) { // Enable display compat mode when display move is involved. return 0; } // If a specific config change is supported by the activity, it's exempted from this compat // treatment. This way, apps can opt out from display compat mode by handling all the config // changes that happen with display move by themselves. final int supportedConfigChanged = mActivityRecord.info.getRealConfigChanged(); return DISPLAY_COMPAT_MODE_CONFIG_MASK & (~supportedConfigChanged); } }
services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java +54 −1 Original line number Diff line number Diff line Loading @@ -22,13 +22,18 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ApplicationInfo.CATEGORY_GAME; import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.WindowConfiguration.WindowingMode; Loading @@ -37,6 +42,9 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager.UserMinAspectRatio; import android.content.res.Configuration; import android.graphics.Rect; import android.view.Display; import android.view.DisplayInfo; import android.view.InputDevice; import android.view.Surface; import androidx.annotation.CallSuper; Loading Loading @@ -188,6 +196,7 @@ class AppCompatActivityRobot { void moveTaskToSecondaryDisplay() { mTaskStack.top().reparent(mSecondaryDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */); mActivityStack.top().ensureActivityConfiguration(); } void setTaskDisplayAreaWindowingMode(@WindowingMode int windowingMode) { Loading Loading @@ -313,6 +322,21 @@ class AppCompatActivityRobot { } } void setTopActivityGame(boolean isGame) { mActivityStack.top().info.applicationInfo.category = isGame ? CATEGORY_GAME : CATEGORY_UNDEFINED; } void setTopActivityResumed() { mActivityStack.top().setVisible(true); mActivityStack.top().setVisibleRequested(true); mActivityStack.top().setState(RESUMED, "setTopActivityResumed"); } void setTopActivityConfigChanges(int supportedConfigChanges) { mActivityStack.top().info.configChanges = supportedConfigChanges; } void setFixedRotationTransformDisplayBounds(@Nullable Rect bounds) { doReturn(bounds).when(mActivityStack.top()).getFixedRotationTransformDisplayBounds(); } Loading @@ -331,9 +355,33 @@ class AppCompatActivityRobot { onPostDisplayContentCreation(mDisplayContent); } /** * Creates a secondary display. Its density, color mode, and touchscreen are intentionally set * different from those of the default display to emulate common physical environments. */ void createSecondaryDisplay() { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayContent.getDisplayInfo()); displayInfo.type = Display.TYPE_EXTERNAL; final int[] hdrTypesWithDv = new int[] {1, 2, 3, 4}; displayInfo.hdrCapabilities = new Display.HdrCapabilities(hdrTypesWithDv, 0, 0, 0); doReturn(true).when(mAtm.mWindowManager).hasHdrSupport(); mSecondaryDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayWidth, mDisplayHeight).build(); new TestDisplayContent.Builder(mAtm, displayInfo).build(); mSecondaryDisplayContent.setForcedDensity(123, mAtm.mWindowManager.mCurrentUserId); final InputDevice device = new InputDevice.Builder() .setAssociatedDisplayId(mSecondaryDisplayContent.mDisplayId) .setSources(InputDevice.SOURCE_TOUCHSCREEN) .build(); final InputDevice[] devices = {device}; doReturn(true).when(mSecondaryDisplayContent.mWmService.mInputManager) .canDispatchToDisplay(device.getId(), mSecondaryDisplayContent.mDisplayId); doReturn(devices).when(mSecondaryDisplayContent.mWmService.mInputManager).getInputDevices(); mAtm.mWindowManager.mIsTouchDevice = true; mAtm.mWindowManager.displayReady(); onPostDisplayContentCreation(mSecondaryDisplayContent); } Loading Loading @@ -421,6 +469,11 @@ class AppCompatActivityRobot { Assert.assertNull(getter.apply(mActivityStack.top())); } void checkTopActivityRelaunched(boolean relaunched) { verify(mActivityStack.top(), times(relaunched ? 1 : 0)).relaunchActivityLocked(anyBoolean(), anyInt()); } void checkTopActivityRecomputedConfiguration() { verify(mActivityStack.top()).recomputeConfiguration(); } Loading
services/tests/wmtests/src/com/android/server/wm/AppCompatDisplayCompatTests.java +30 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.CONFIG_COLOR_MODE; import static android.content.pm.ActivityInfo.CONFIG_DENSITY; import static android.content.pm.ActivityInfo.CONFIG_RESOURCES_UNUSED; import static android.content.pm.ActivityInfo.CONFIG_TOUCHSCREEN; import static com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_COMPAT_MODE; import static com.android.window.flags.Flags.FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS; import static org.junit.Assert.assertEquals; Loading @@ -42,15 +48,22 @@ import java.util.function.Consumer; @RunWith(WindowTestRunner.class) public class AppCompatDisplayCompatTests extends WindowTestsBase { @EnableFlags(FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS) private static final int CONFIG_MASK_FOR_DISPLAY_MOVE = ~(CONFIG_DENSITY | CONFIG_TOUCHSCREEN | CONFIG_COLOR_MODE | CONFIG_RESOURCES_UNUSED); @EnableFlags({FLAG_ENABLE_DISPLAY_COMPAT_MODE, FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS}) @Test public void testRestartMenuVisibility() { public void testDisplayCompatMode_gameDoesNotRestartWithDisplayMove() { runTestScenario((robot) -> { robot.activity().createSecondaryDisplay(); robot.activity().createActivityWithComponent(); robot.activity().setTopActivityGame(true); robot.activity().setTopActivityResumed(); robot.activity().setTopActivityConfigChanges(CONFIG_MASK_FOR_DISPLAY_MOVE); robot.checkRestartMenuVisibility(false); robot.activity().moveTaskToSecondaryDisplay(); robot.activity().checkTopActivityRelaunched(false); robot.checkRestartMenuVisibility(true); robot.activity().applyToTopActivity(ActivityRecord::restartProcessIfVisible); Loading @@ -58,6 +71,21 @@ public class AppCompatDisplayCompatTests extends WindowTestsBase { }); } @Test public void testDisplayCompatMode_nonGameRestartsWithDisplayMove() { runTestScenario((robot) -> { robot.activity().createSecondaryDisplay(); robot.activity().createActivityWithComponent(); robot.activity().setTopActivityResumed(); robot.activity().setTopActivityConfigChanges(CONFIG_MASK_FOR_DISPLAY_MOVE); robot.checkRestartMenuVisibility(false); robot.activity().moveTaskToSecondaryDisplay(); robot.activity().checkTopActivityRelaunched(true); robot.checkRestartMenuVisibility(false); }); } void runTestScenario(@NonNull Consumer<DisplayCompatRobotTest> consumer) { final DisplayCompatRobotTest robot = new DisplayCompatRobotTest(mWm, mAtm, mSupervisor); consumer.accept(robot); Loading