diff options
| author | 2022-12-30 11:23:51 +0000 | |
|---|---|---|
| committer | 2022-12-30 11:23:51 +0000 | |
| commit | 5b8432af7ef4406cadc3e85bc2392b1815e78bcc (patch) | |
| tree | a72fbcc363de0b89bd5d309ba3e1c663c60163fe | |
| parent | 149945dec942d52621755c3705b72775a391c3d5 (diff) | |
| parent | f4fa9297859b5facb814e27c6fc26859a0bcf3ec (diff) | |
Merge "Add per-app controls for compat fake focus" into tm-qpr-dev am: f4fa929785
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20787908
Change-Id: Iacacebe098cada1fc8d7446c0a75b62c8a71608d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
5 files changed, 184 insertions, 8 deletions
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 4be5e148102e..06399b958159 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1129,6 +1129,17 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public static final long OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN = 218959984L; /** + * Enables sending fake focus for unfocused apps in splitscreen. Some game engines + * wait to get focus before drawing the content of the app so fake focus helps them to avoid + * staying blacked out when they are resumed and do not have focus yet. + * @hide + */ + @ChangeId + @Disabled + @Overridable + public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L; + + /** * Compares activity window layout min width/height with require space for multi window to * determine if it can be put into multi window mode. */ diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f38633fb0e6c..c712167c4cd1 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -10127,8 +10127,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when // covered with bubbles. boolean shouldSendCompatFakeFocus() { - return mWmService.mLetterboxConfiguration.isCompatFakeFocusEnabled() && inMultiWindowMode() - && !inPinnedWindowingMode() && !inFreeformWindowingMode(); + return mWmService.mLetterboxConfiguration.isCompatFakeFocusEnabled(info) + && inMultiWindowMode() && !inPinnedWindowingMode() && !inFreeformWindowingMode(); } static class Builder { diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 03c558924430..9b8423327215 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -23,6 +23,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.graphics.Color; import android.provider.DeviceConfig; import android.util.Slog; @@ -39,6 +41,10 @@ final class LetterboxConfiguration { private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxConfiguration" : TAG_ATM; + @VisibleForTesting + static final String DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS = + "enable_compat_fake_focus"; + /** * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with * set-fixed-orientation-letterbox-aspect-ratio or via {@link @@ -108,6 +114,12 @@ final class LetterboxConfiguration { /** Letterboxed app window is aligned to the right side. */ static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2; + @VisibleForTesting + static final String PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN = "com.android.COMPAT_FAKE_FOCUS_OPT_IN"; + @VisibleForTesting + static final String PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT = + "com.android.COMPAT_FAKE_FOCUS_OPT_OUT"; + final Context mContext; // Responsible for the persistence of letterbox[Horizontal|Vertical]PositionMultiplier @@ -977,11 +989,49 @@ final class LetterboxConfiguration { "enable_translucent_activity_letterbox", false); } - // TODO(b/262866240): Add listener to check for device config property + @VisibleForTesting + boolean getPackageManagerProperty(PackageManager pm, String property) { + boolean enabled = false; + try { + final PackageManager.Property p = pm.getProperty(property, mContext.getPackageName()); + enabled = p.getBoolean(); + } catch (PackageManager.NameNotFoundException e) { + // Property not found + } + return enabled; + } + + @VisibleForTesting + boolean isCompatFakeFocusEnabled(ActivityInfo info) { + if (!isCompatFakeFocusEnabledOnDevice()) { + return false; + } + // See if the developer has chosen to opt in / out of treatment + PackageManager pm = mContext.getPackageManager(); + if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT)) { + return false; + } else if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN)) { + return true; + } + if (info.isChangeEnabled(ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS)) { + return true; + } + return false; + } + /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ - boolean isCompatFakeFocusEnabled() { - return mIsCompatFakeFocusEnabled && DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER, "enable_compat_fake_focus", true); + boolean isCompatFakeFocusEnabledOnDevice() { + return mIsCompatFakeFocusEnabled + && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, true); + } + + /** + * Overrides whether fake sending focus is enabled for unfocused apps in splitscreen + */ + @VisibleForTesting + void setIsCompatFakeFocusEnabled(boolean enabled) { + mIsCompatFakeFocusEnabled = enabled; } /** Whether camera compatibility treatment is enabled. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java index e19670458bb7..ead1a8675775 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.wm.LetterboxConfiguration.DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT; @@ -25,6 +26,8 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_RE import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -34,6 +37,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; import androidx.test.filters.SmallTest; @@ -43,18 +47,25 @@ import org.junit.Test; import java.util.Arrays; import java.util.function.BiConsumer; +/** + * Tests for the {@link LetterboxConfiguration} class. + * + * Build/Install/Run: + * atest WmTests:LetterboxConfigurationTests + */ @SmallTest @Presubmit public class LetterboxConfigurationTest { + private Context mContext; private LetterboxConfiguration mLetterboxConfiguration; private LetterboxConfigurationPersister mLetterboxConfigurationPersister; @Before public void setUp() throws Exception { - Context context = getInstrumentation().getTargetContext(); + mContext = getInstrumentation().getTargetContext(); mLetterboxConfigurationPersister = mock(LetterboxConfigurationPersister.class); - mLetterboxConfiguration = new LetterboxConfiguration(context, + mLetterboxConfiguration = new LetterboxConfiguration(mContext, mLetterboxConfigurationPersister); } @@ -222,6 +233,34 @@ public class LetterboxConfigurationTest { LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop); } + @Test + public void testIsCompatFakeFocusEnabledOnDevice() { + boolean wasFakeFocusEnabled = DeviceConfig + .getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, false); + + // Set runtime flag to true and build time flag to false + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); + mLetterboxConfiguration.setIsCompatFakeFocusEnabled(false); + assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); + + // Set runtime flag to false and build time flag to true + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "false", false); + mLetterboxConfiguration.setIsCompatFakeFocusEnabled(true); + assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); + + // Set runtime flag to true so that both are enabled + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); + assertTrue(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); + + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, Boolean.toString(wasFakeFocusEnabled), + false); + } + private void assertForHorizontalMove(int from, int expected, int expectedTime, boolean halfFoldPose, BiConsumer<LetterboxConfiguration, Boolean> move) { // We are in the current position 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 7488e1c113ab..e9080ab78fbc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -53,6 +53,8 @@ import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.STOPPED; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; +import static com.android.server.wm.LetterboxConfiguration.PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN; +import static com.android.server.wm.LetterboxConfiguration.PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; @@ -3228,6 +3230,80 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(newDensity, mActivity.getConfiguration().densityDpi); } + private ActivityRecord setUpActivityForCompatFakeFocusTest() { + 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(); + task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + spyOn(activity.mWmService.mLetterboxConfiguration); + doReturn(true).when(activity.mWmService.mLetterboxConfiguration) + .isCompatFakeFocusEnabledOnDevice(); + return activity; + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideEnabled_returnsTrue() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + + assertTrue(activity.shouldSendCompatFakeFocus()); + } + + @Test + @DisableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testShouldSendFakeFocus_overrideDisabled_returnsFalse() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + + assertFalse(activity.shouldSendCompatFakeFocus()); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testIsCompatFakeFocusEnabled_optOutPropertyAndOverrideEnabled_fakeFocusDisabled() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + doReturn(true).when(activity.mWmService.mLetterboxConfiguration) + .getPackageManagerProperty(any(), eq(PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT)); + + assertFalse(activity.mWmService.mLetterboxConfiguration + .isCompatFakeFocusEnabled(activity.info)); + } + + @Test + @DisableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS}) + public void testIsCompatFakeFocusEnabled_optInPropertyEnabled_noOverride_fakeFocusEnabled() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + doReturn(true).when(activity.mWmService.mLetterboxConfiguration) + .getPackageManagerProperty(any(), eq(PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN)); + + assertTrue(activity.mWmService.mLetterboxConfiguration + .isCompatFakeFocusEnabled(activity.info)); + } + + @Test + public void testIsCompatFakeFocusEnabled_optOutPropertyEnabled_fakeFocusDisabled() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + doReturn(true).when(activity.mWmService.mLetterboxConfiguration) + .getPackageManagerProperty(any(), eq(PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT)); + + assertFalse(activity.mWmService.mLetterboxConfiguration + .isCompatFakeFocusEnabled(activity.info)); + } + + @Test + public void testIsCompatFakeFocusEnabled_optInPropertyEnabled_fakeFocusEnabled() { + ActivityRecord activity = setUpActivityForCompatFakeFocusTest(); + doReturn(true).when(activity.mWmService.mLetterboxConfiguration) + .getPackageManagerProperty(any(), eq(PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN)); + + assertTrue(activity.mWmService.mLetterboxConfiguration + .isCompatFakeFocusEnabled(activity.info)); + } + private int getExpectedSplitSize(int dimensionToSplit) { int dividerWindowWidth = mActivity.mWmService.mContext.getResources().getDimensionPixelSize( |