Merge "Add per-app controls for compat fake focus" into tm-qpr-dev
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4be5e14..06399b9 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1129,6 +1129,17 @@
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 f38633f..c712167 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 @@
// 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 03c5589..9b84233 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.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 @@
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 @@
/** 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 @@
"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 e196704..ead1a86 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 @@
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_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 android.content.Context;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
@@ -43,18 +47,25 @@
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 @@
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 7488e1c..e9080ab 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.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 @@
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(