diff options
12 files changed, 552 insertions, 171 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 4da7e5325ed5..d039b048a3e4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -10890,12 +10890,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Whether we should send fake focus when the activity is resumed. This is done because some * game engines wait to get focus before drawing the content of the app. */ - // TODO(b/263593361): Explore enabling compat fake focus for freeform. - // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when - // covered with bubbles. boolean shouldSendCompatFakeFocus() { - return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode() - && !inPinnedWindowingMode() && !inFreeformWindowingMode(); + return mAppCompatController.getAppCompatFocusOverrides().shouldSendFakeFocus(); } boolean canCaptureSnapshot() { diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java index f9e2507aa1eb..998d65d84b3d 100644 --- a/services/core/java/com/android/server/wm/AppCompatController.java +++ b/services/core/java/com/android/server/wm/AppCompatController.java @@ -94,4 +94,9 @@ class AppCompatController { } return null; } + + @NonNull + AppCompatFocusOverrides getAppCompatFocusOverrides() { + return mAppCompatOverrides.getAppCompatFocusOverrides(); + } } diff --git a/services/core/java/com/android/server/wm/AppCompatFocusOverrides.java b/services/core/java/com/android/server/wm/AppCompatFocusOverrides.java new file mode 100644 index 000000000000..ab4bb140f3a6 --- /dev/null +++ b/services/core/java/com/android/server/wm/AppCompatFocusOverrides.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 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 com.android.server.wm; + +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; +import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; + +import static com.android.server.wm.AppCompatUtils.isChangeEnabled; + +import android.annotation.NonNull; + +import com.android.server.wm.utils.OptPropFactory; + +/** + * Encapsulates app compat focus policy. + */ +class AppCompatFocusOverrides { + + @NonNull + final ActivityRecord mActivityRecord; + @NonNull + private final OptPropFactory.OptProp mFakeFocusOptProp; + + AppCompatFocusOverrides(@NonNull ActivityRecord activityRecord, + @NonNull AppCompatConfiguration appCompatConfiguration, + @NonNull OptPropFactory optPropBuilder) { + mActivityRecord = activityRecord; + mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, + appCompatConfiguration::isCompatFakeFocusEnabled); + } + + /** + * Whether sending compat fake focus for split screen resumed activities is enabled. Needed + * because some game engines wait to get focus before drawing the content of the app which isn't + * guaranteed by default in multi-window modes. + * + * <p>This treatment is enabled when the following conditions are met: + * <ul> + * <li>Flag gating the treatment is enabled + * <li>Component property is NOT set to false + * <li>Component property is set to true or per-app override is enabled + * </ul> + */ + boolean shouldSendFakeFocus() { + // TODO(b/263593361): Explore enabling compat fake focus for freeform. + // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when + // covered with bubbles. + return mFakeFocusOptProp.shouldEnableWithOverrideAndProperty( + isChangeEnabled(mActivityRecord, OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS)) + && mActivityRecord.inMultiWindowMode() && !mActivityRecord.inPinnedWindowingMode() + && !mActivityRecord.inFreeformWindowingMode(); + } + +} diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java index b611ba9bb065..cde48d64d398 100644 --- a/services/core/java/com/android/server/wm/AppCompatOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java @@ -18,17 +18,12 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP; import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP; -import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES; -import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; - -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.NonNull; @@ -39,17 +34,10 @@ import com.android.server.wm.utils.OptPropFactory; */ public class AppCompatOverrides { - private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatOverrides" : TAG_ATM; - - @NonNull - private final AppCompatConfiguration mAppCompatConfiguration; - @NonNull private final ActivityRecord mActivityRecord; @NonNull - private final OptPropFactory.OptProp mFakeFocusOptProp; - @NonNull private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp; @NonNull private final OptPropFactory.OptProp mAllowDisplayOrientationOverrideOptProp; @@ -61,26 +49,25 @@ public class AppCompatOverrides { private final AppCompatCameraOverrides mAppCompatCameraOverrides; @NonNull private final AppCompatAspectRatioOverrides mAppCompatAspectRatioOverrides; + @NonNull + private final AppCompatFocusOverrides mAppCompatFocusOverrides; AppCompatOverrides(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration, @NonNull OptPropFactory optPropBuilder) { - mAppCompatConfiguration = appCompatConfiguration; mActivityRecord = activityRecord; mAppCompatCameraOverrides = new AppCompatCameraOverrides(mActivityRecord, - mAppCompatConfiguration, optPropBuilder); + appCompatConfiguration, optPropBuilder); mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord, - mAppCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides); + appCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides); // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with reachability. mAppCompatAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord, - mAppCompatConfiguration, optPropBuilder, + appCompatConfiguration, optPropBuilder, activityRecord.mLetterboxUiController::isDisplayFullScreenAndInPosture, activityRecord.mLetterboxUiController::getHorizontalPositionMultiplier); - - mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, - mAppCompatConfiguration::isCompatFakeFocusEnabled); - + mAppCompatFocusOverrides = new AppCompatFocusOverrides(mActivityRecord, + appCompatConfiguration, optPropBuilder); mAllowOrientationOverrideOptProp = optPropBuilder.create( PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE); @@ -114,21 +101,9 @@ public class AppCompatOverrides { return mAppCompatAspectRatioOverrides; } - /** - * Whether sending compat fake focus for split screen resumed activities is enabled. Needed - * because some game engines wait to get focus before drawing the content of the app which isn't - * guaranteed by default in multi-window modes. - * - * <p>This treatment is enabled when the following conditions are met: - * <ul> - * <li>Flag gating the treatment is enabled - * <li>Component property is NOT set to false - * <li>Component property is set to true or per-app override is enabled - * </ul> - */ - boolean shouldSendFakeFocus() { - return mFakeFocusOptProp.shouldEnableWithOverrideAndProperty( - isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS)); + @NonNull + AppCompatFocusOverrides getAppCompatFocusOverrides() { + return mAppCompatFocusOverrides; } boolean isAllowOrientationOverrideOptOut() { diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java index 1b30a20d3e9a..fd816067fbad 100644 --- a/services/core/java/com/android/server/wm/AppCompatUtils.java +++ b/services/core/java/com/android/server/wm/AppCompatUtils.java @@ -73,4 +73,13 @@ class AppCompatUtils { static boolean isInVrUiMode(Configuration config) { return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET; } + + /** + * @param activityRecord The {@link ActivityRecord} for the app package. + * @param overrideChangeId The per-app override identifier. + * @return {@code true} if the per-app override is enable for the given activity. + */ + static boolean isChangeEnabled(@NonNull ActivityRecord activityRecord, long overrideChangeId) { + return activityRecord.info.isChangeEnabled(overrideChangeId); + } } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index be8e806a5752..73f36557f3d6 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -117,22 +117,6 @@ final class LetterboxUiController { } /** - * Whether sending compat fake focus for split screen resumed activities is enabled. Needed - * because some game engines wait to get focus before drawing the content of the app which isn't - * guaranteed by default in multi-window modes. - * - * <p>This treatment is enabled when the following conditions are met: - * <ul> - * <li>Flag gating the treatment is enabled - * <li>Component property is NOT set to false - * <li>Component property is set to true or per-app override is enabled - * </ul> - */ - boolean shouldSendFakeFocus() { - return getAppCompatOverrides().shouldSendFakeFocus(); - } - - /** * Whether we should apply the force resize per-app override. When this override is applied it * forces the packages it is applied to to be resizable. It won't change whether the app can be * put into multi-windowing mode, but allow the app to resize without going into size-compat diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java index 867f01fd4699..11f7560a1409 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +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; @@ -190,6 +193,27 @@ class AppCompatActivityRobot { doReturn(embedded).when(mActivityStack.top()).isEmbedded(); } + void setTopActivityInMultiWindowMode(boolean multiWindowMode) { + doReturn(multiWindowMode).when(mActivityStack.top()).inMultiWindowMode(); + if (multiWindowMode) { + doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivityStack.top()).getWindowingMode(); + } + } + + void setTopActivityInPinnedWindowingMode(boolean pinnedWindowingMode) { + doReturn(pinnedWindowingMode).when(mActivityStack.top()).inPinnedWindowingMode(); + if (pinnedWindowingMode) { + doReturn(WINDOWING_MODE_PINNED).when(mActivityStack.top()).getWindowingMode(); + } + } + + void setTopActivityInFreeformWindowingMode(boolean freeformWindowingMode) { + doReturn(freeformWindowingMode).when(mActivityStack.top()).inFreeformWindowingMode(); + if (freeformWindowingMode) { + doReturn(WINDOWING_MODE_FREEFORM).when(mActivityStack.top()).getWindowingMode(); + } + } + void destroyTopActivity() { mActivityStack.top().removeImmediately(); } @@ -401,9 +425,11 @@ class AppCompatActivityRobot { private void pushActivity(@NonNull ActivityRecord activity) { mActivityStack.push(activity); spyOn(activity); + // TODO (b/351763164): Use these spyOn calls only when necessary. spyOn(activity.mAppCompatController.getTransparentPolicy()); spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides()); spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy()); + spyOn(activity.mAppCompatController.getAppCompatFocusOverrides()); spyOn(activity.mLetterboxUiController); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java index 0a1b16bfc3e9..00a87719eaac 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java @@ -66,4 +66,8 @@ class AppCompatConfigurationRobot { doReturn(enabled).when(mAppCompatConfiguration) .isCameraCompatSplitScreenAspectRatioEnabled(); } + + void enableCompatFakeFocus(boolean enabled) { + doReturn(enabled).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java new file mode 100644 index 000000000000..27c5e4ebb397 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2024 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 com.android.server.wm; + +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; +import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import android.compat.testing.PlatformCompatChangeRule; +import android.platform.test.annotations.Presubmit; + +import androidx.annotation.NonNull; + +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.testng.Assert; + +import java.util.function.Consumer; + +/** + * Test class for {@link AppCompatFocusOverrides}. + * <p> + * Build/Install/Run: + * atest WmTests:AppCompatFocusOverridesTest + */ +@Presubmit +@RunWith(WindowTestRunner.class) +public class AppCompatFocusOverridesTest extends WindowTestsBase { + + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideEnabled_inMultiWindow_returnsTrue() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ true); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideEnabled_noMultiWindowMode_returnsFalse() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ false); + }); + + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideEnabled_pinnedWindowMode_returnsFalse() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInPinnedWindowingMode(/* multiWindowMode */ true); + }); + + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideEnabled_freeformMode_returnsFalse() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInFreeformWindowingMode(/* freeformWindowingMode */ true); + }); + + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideDisabled_returnsFalse() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testIsCompatFakeFocusEnabled_propertyDisabledAndOverrideOn_fakeFocusDisabled() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().disable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testIsCompatFakeFocusEnabled_propertyEnabled_noOverride_fakeFocusEnabled() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().enable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ true); + }); + } + + @Test + public void testIsCompatFakeFocusEnabled_propertyDisabled_fakeFocusDisabled() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().disable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ false); + }); + } + + @Test + public void testIsCompatFakeFocusEnabled_propertyEnabled_fakeFocusEnabled() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().enable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.applyOnActivity((a) -> { + a.createActivityWithComponent(); + a.setTopActivityInMultiWindowMode(/* multiWindowMode */ true); + }); + robot.checkShouldSendFakeFocusOnTopActivity(/* expected */ true); + }); + } + + /** + * Runs a test scenario providing a Robot. + */ + void runTestScenario(@NonNull Consumer<FocusOverridesRobotTest> consumer) { + spyOn(mWm.mAppCompatConfiguration); + final FocusOverridesRobotTest robot = new FocusOverridesRobotTest(mWm, mAtm, mSupervisor); + consumer.accept(robot); + } + + private static class FocusOverridesRobotTest extends AppCompatRobotBase { + + FocusOverridesRobotTest(@NonNull WindowManagerService wm, + @NonNull ActivityTaskManagerService atm, + @NonNull ActivityTaskSupervisor supervisor) { + super(wm, atm, supervisor); + } + + void checkShouldSendFakeFocusOnTopActivity(boolean expected) { + Assert.assertEquals(activity().top().mAppCompatController.getAppCompatFocusOverrides() + .shouldSendFakeFocus(), expected); + } + } + +} diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatSizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatSizeCompatTests.java new file mode 100644 index 000000000000..439c6337d905 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatSizeCompatTests.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2024 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 com.android.server.wm; + +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; +import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import android.compat.testing.PlatformCompatChangeRule; +import android.platform.test.annotations.Presubmit; + +import androidx.annotation.NonNull; +import androidx.test.filters.MediumTest; + +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; + +import java.util.function.Consumer; + +/** + * Tests for App Compat specific code about sizes. + * + * Build/Install/Run: + * atest WmTests:AppCompatSizeCompatTests + */ +@MediumTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class AppCompatSizeCompatTests extends WindowTestsBase { + + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusEnabledUnsetProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ true); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusEnabledTrueProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().enable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ true); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusEnabledFalseProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().disable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusDisabledUnsetProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusDisabledTrueProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().enable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ true); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusDisabledFalseProp() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ true); + robot.prop().disable(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_compatFakeFocusEnabledFeatureDisabled() { + runTestScenario((robot) -> { + robot.conf().enableCompatFakeFocus(/* enabled */ false); + robot.activity().createActivityWithComponent(); + + robot.putTopActivityInMultiWindowMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInPinnedWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + + robot.putTopActivityInFreeformWindowingMode(); + robot.checkShouldSendCompatFakeFocus(/* expected */ false); + }); + } + + /** + * Runs a test scenario providing a Robot. + */ + void runTestScenario(@NonNull Consumer<SizeCompatRobotTest> consumer) { + spyOn(mWm.mAppCompatConfiguration); + final SizeCompatRobotTest robot = new SizeCompatRobotTest(mWm, mAtm, mSupervisor); + consumer.accept(robot); + } + + private static class SizeCompatRobotTest extends AppCompatRobotBase { + + SizeCompatRobotTest(@NonNull WindowManagerService wm, + @NonNull ActivityTaskManagerService atm, + @NonNull ActivityTaskSupervisor supervisor) { + super(wm, atm, supervisor); + } + + void checkShouldSendCompatFakeFocus(boolean expected) { + Assert.assertEquals(expected, activity().top().shouldSendCompatFakeFocus()); + } + + void putTopActivityInMultiWindowMode() { + applyOnActivity((a) -> { + a.setTopActivityInMultiWindowMode(true); + a.setTopActivityInFreeformWindowingMode(false); + a.setTopActivityInPinnedWindowingMode(false); + }); + } + + void putTopActivityInPinnedWindowingMode() { + applyOnActivity((a) -> { + a.setTopActivityInMultiWindowMode(false); + a.setTopActivityInPinnedWindowingMode(true); + a.setTopActivityInFreeformWindowingMode(false); + }); + } + + void putTopActivityInFreeformWindowingMode() { + applyOnActivity((a) -> { + a.setTopActivityInMultiWindowMode(false); + a.setTopActivityInPinnedWindowingMode(false); + a.setTopActivityInFreeformWindowingMode(true); + }); + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 44c7057b2294..a0a29048fe26 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -18,14 +18,12 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP; import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP; -import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES; -import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; @@ -362,72 +360,6 @@ public class LetterboxUiControllerTest extends WindowTestsBase { } @Test - @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) - public void testShouldSendFakeFocus_overrideEnabled_returnsTrue() { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - - mController = new LetterboxUiController(mWm, mActivity); - - assertTrue(mController.shouldSendFakeFocus()); - } - - @Test - @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) - public void testShouldSendFakeFocus_overrideDisabled_returnsFalse() { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - - mController = new LetterboxUiController(mWm, mActivity); - - assertFalse(mController.shouldSendFakeFocus()); - } - - @Test - @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) - public void testIsCompatFakeFocusEnabled_propertyDisabledAndOverrideEnabled_fakeFocusDisabled() - throws Exception { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - mockThatProperty(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, /* value */ false); - - mController = new LetterboxUiController(mWm, mActivity); - - assertFalse(mController.shouldSendFakeFocus()); - } - - @Test - @DisableCompatChanges({OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) - public void testIsCompatFakeFocusEnabled_propertyEnabled_noOverride_fakeFocusEnabled() - throws Exception { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - mockThatProperty(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, /* value */ true); - - mController = new LetterboxUiController(mWm, mActivity); - - assertTrue(mController.shouldSendFakeFocus()); - } - - @Test - public void testIsCompatFakeFocusEnabled_propertyDisabled_fakeFocusDisabled() - throws Exception { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - mockThatProperty(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, /* value */ false); - - mController = new LetterboxUiController(mWm, mActivity); - - assertFalse(mController.shouldSendFakeFocus()); - } - - @Test - public void testIsCompatFakeFocusEnabled_propertyEnabled_fakeFocusEnabled() - throws Exception { - doReturn(true).when(mAppCompatConfiguration).isCompatFakeFocusEnabled(); - mockThatProperty(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS, /* value */ true); - - mController = new LetterboxUiController(mWm, mActivity); - - assertTrue(mController.shouldSendFakeFocus()); - } - - @Test @EnableCompatChanges({FORCE_RESIZE_APP}) public void testshouldOverrideForceResizeApp_overrideEnabled_returnsTrue() { mController = new LetterboxUiController(mWm, mActivity); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 8981f715cf4b..72747c974694 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; @@ -4809,52 +4808,6 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(newDensity, mActivity.getConfiguration().densityDpi); } - @Test - public void testShouldSendFakeFocus_compatFakeFocusEnabled() { - final ActivityRecord activity = new ActivityBuilder(mAtm) - .setCreateTask(true) - .setOnTop(true) - // Set the component to be that of the test class in order to enable compat changes - .setComponent(ComponentName.createRelative(mContext, - com.android.server.wm.SizeCompatTests.class.getName())) - .build(); - final Task task = activity.getTask(); - spyOn(activity.mLetterboxUiController); - doReturn(true).when(activity.mLetterboxUiController).shouldSendFakeFocus(); - - task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - assertTrue(activity.shouldSendCompatFakeFocus()); - - task.setWindowingMode(WINDOWING_MODE_PINNED); - assertFalse(activity.shouldSendCompatFakeFocus()); - - task.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertFalse(activity.shouldSendCompatFakeFocus()); - } - - @Test - public void testShouldSendFakeFocus_compatFakeFocusDisabled() { - final ActivityRecord activity = new ActivityBuilder(mAtm) - .setCreateTask(true) - .setOnTop(true) - // Set the component to be that of the test class in order to enable compat changes - .setComponent(ComponentName.createRelative(mContext, - com.android.server.wm.SizeCompatTests.class.getName())) - .build(); - final Task task = activity.getTask(); - spyOn(activity.mLetterboxUiController); - doReturn(false).when(activity.mLetterboxUiController).shouldSendFakeFocus(); - - task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - assertFalse(activity.shouldSendCompatFakeFocus()); - - task.setWindowingMode(WINDOWING_MODE_PINNED); - assertFalse(activity.shouldSendCompatFakeFocus()); - - task.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertFalse(activity.shouldSendCompatFakeFocus()); - } - private void setUpAllowThinLetterboxed(boolean thinLetterboxAllowed) { spyOn(mActivity.mLetterboxUiController); doReturn(thinLetterboxAllowed).when(mActivity.mLetterboxUiController) |