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>
This commit is contained in:
Mariia Sandrikova
2022-12-30 11:23:51 +00:00
committed by Automerger Merge Worker
5 changed files with 184 additions and 8 deletions

View File

@@ -1128,6 +1128,17 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
@Overridable
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.

View File

@@ -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 {

View File

@@ -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. */

View File

@@ -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

View File

@@ -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(