Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4fa9297 authored by Mariia Sandrikova's avatar Mariia Sandrikova Committed by Android (Google) Code Review
Browse files

Merge "Add per-app controls for compat fake focus" into tm-qpr-dev

parents 62a83980 c243a01d
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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.
+2 −2
Original line number Diff line number Diff line
@@ -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 {
+54 −4
Original line number Diff line number Diff line
@@ -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. */
+41 −2
Original line number Diff line number Diff line
@@ -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
+76 −0
Original line number Diff line number Diff line
@@ -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(