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

Commit b5f9f849 authored by Candice's avatar Candice
Browse files

Change the order of how forceDark and forceInvert are applied

We should respect app's configuration to use ForceDark(AutoDark) for its
dark theme before we apply the colors by system through ForceInvertDark.

Bug: 391959649
Bug: 297556388
Test: atest ViewRootImplTest
Flag: android.view.accessibility.force_invert_color
Change-Id: I0cf8f90df51d42083793a7c5d66b52c14dbca980
parent d8211818
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -2057,6 +2057,21 @@ public final class ViewRootImpl implements ViewParent,
    public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
        try {
            // Checking if the app choose to apply AutoDark for its dark theme before applying
            // forceInvertDark from the system.
            boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
            if (useAutoDark) {
                boolean forceDarkAllowedDefault =
                        SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
                useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
                        && a.getBoolean(R.styleable.Theme_forceDarkAllowed,
                            forceDarkAllowedDefault);
                if (useAutoDark) {
                    return ForceDarkType.FORCE_DARK;
                }
            }
            if (forceInvertColor()) {
                // Force invert ignores all developer opt-outs.
                // We also ignore dark theme, since the app developer can override the user's
@@ -2076,15 +2091,7 @@ public final class ViewRootImpl implements ViewParent,
                }
            }
            boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
            if (useAutoDark) {
                boolean forceDarkAllowedDefault =
                        SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
                useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
                        && a.getBoolean(R.styleable.Theme_forceDarkAllowed,
                            forceDarkAllowedDefault);
            }
            return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
            return ForceDarkType.NONE;
        } finally {
            a.recycle();
        }
+18 −0
Original line number Diff line number Diff line
@@ -95,4 +95,22 @@
        <item name="android:height">200px</item>
    </style>

    <style name="ForceDarkAllowed" />
    <style name="ForceDarkAllowed.Light">
        <item name="android:isLightTheme">true</item>
        <item name="android:forceDarkAllowed">true</item>
    </style>
    <style name="ForceDarkAllowed.Dark">
        <item name="android:isLightTheme">false</item>
        <item name="android:forceDarkAllowed">true</item>
    </style>
    <style name="ForceDarkAllowedFalse" />
    <style name="ForceDarkAllowedFalse.Light">
        <item name="android:isLightTheme">true</item>
        <item name="android:forceDarkAllowed">false</item>
    </style>
    <style name="ForceDarkAllowedFalse.Dark">
        <item name="android:isLightTheme">false</item>
        <item name="android:forceDarkAllowed">false</item>
    </style>
</resources>
+48 −45
Original line number Diff line number Diff line
@@ -24,8 +24,8 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -58,7 +58,6 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import android.annotation.NonNull;
import android.app.Instrumentation;
@@ -68,7 +67,6 @@ import android.graphics.ForceDarkType;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.os.SystemProperties;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -91,6 +89,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.TestUtils;
import com.android.cts.input.BlockingQueueEventVerifier;
import com.android.frameworks.coretests.R;
import com.android.window.flags.Flags;

import org.hamcrest.Matcher;
@@ -168,8 +167,6 @@ public class ViewRootImplTest {

            var uiModeManager = sContext.getSystemService(UiModeManager.class);
            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);

            setForceDarkSysProp(false);
        });
        if (mView != null) {
            sInstrumentation.runOnMainSync(() -> {
@@ -1482,7 +1479,7 @@ public class ViewRootImplTest {
        waitForSystemNightModeActivated(true);
        enableForceInvertColor(true);

        setUpViewAttributes(/* isLightTheme= */ true);
        setUpViewAttributes(/* isLightTheme= */ true, /* isForceDarkAllowed= */ false);

        TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
                () -> (mViewRootImpl.determineForceDarkType()
@@ -1496,7 +1493,7 @@ public class ViewRootImplTest {
        waitForSystemNightModeActivated(true);
        enableForceInvertColor(true);

        setUpViewAttributes(/* isLightTheme= */ false);
        setUpViewAttributes(/* isLightTheme= */ false, /* isForceDarkAllowed= */ false);

        TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
                () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
@@ -1505,19 +1502,14 @@ public class ViewRootImplTest {
    @Test
    @EnableFlags(FLAG_FORCE_INVERT_COLOR)
    public void forceInvertOffForceDarkOff_forceDarkModeDisabled() {
        ShellIdentityUtils.invokeWithShellPermissions(() -> {
            Settings.Secure.putInt(
                    sContext.getContentResolver(),
                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
                    /* value= */ 0
            );

            // TODO(b/297556388): figure out how to set this without getting blocked by SELinux
            assumeTrue(setForceDarkSysProp(true));
        });
        // Set up configurations for force invert color
        waitForSystemNightModeActivated(true);
        enableForceInvertColor(false);

        sInstrumentation.runOnMainSync(() ->
                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
        // Set up view attributes
        setUpViewAttributes(
                /* isLightTheme= */ false,
                /* isForceDarkAllowed= */ false);

        assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE);
    }
@@ -1525,18 +1517,29 @@ public class ViewRootImplTest {
    @Test
    @EnableFlags(FLAG_FORCE_INVERT_COLOR)
    public void forceInvertOffForceDarkOn_forceDarkModeEnabled() {
        ShellIdentityUtils.invokeWithShellPermissions(() -> {
            Settings.Secure.putInt(
                    sContext.getContentResolver(),
                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
                    /* value= */ 0
            );
        // Set up configurations for force invert color
        waitForSystemNightModeActivated(true);
        enableForceInvertColor(false);

            assumeTrue(setForceDarkSysProp(true));
        });
        // Set up view attributes
        setUpViewAttributes(
                /* isLightTheme= */ true,
                /* isForceDarkAllowed= */ true);

        sInstrumentation.runOnMainSync(() ->
                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
        assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK);
    }

    @Test
    @EnableFlags(FLAG_FORCE_INVERT_COLOR)
    public void forceInvertOnForceDarkOn_forceDarkModeEnabled() {
        // Set up configurations for force invert color
        waitForSystemNightModeActivated(true);
        enableForceInvertColor(true);

        // Setup view attributes
        setUpViewAttributes(
                /* isLightTheme= */ true,
                /* isForceDarkAllowed= */ true);

        assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK);
    }
@@ -1624,19 +1627,6 @@ public class ViewRootImplTest {
        assertThat(bounds.height()).isAtLeast(strokeWidth * 2);
    }

    private boolean setForceDarkSysProp(boolean isForceDarkEnabled) {
        try {
            SystemProperties.set(
                    ThreadedRenderer.DEBUG_FORCE_DARK,
                    Boolean.toString(isForceDarkEnabled)
            );
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Failed to set force_dark sysprop", e);
            return false;
        }
    }

    static class InputView extends View {
        private final BlockingQueue<InputEvent> mEvents = new LinkedBlockingQueue<>();
        private final BlockingQueueEventVerifier mVerifier =
@@ -1763,10 +1753,23 @@ public class ViewRootImplTest {
        });
    }

    private void setUpViewAttributes(boolean isLightTheme) {
    private void setUpViewAttributes(boolean isLightTheme, boolean isForceDarkAllowed) {
        ShellIdentityUtils.invokeWithShellPermissions(() -> {
            sContext.setTheme(isLightTheme ? android.R.style.Theme_DeviceDefault_Light
                    : android.R.style.Theme_DeviceDefault);
            int themeId;
            if (isForceDarkAllowed) {
                if (isLightTheme) {
                    themeId = R.style.ForceDarkAllowed_Light;
                } else {
                    themeId = R.style.ForceDarkAllowed_Dark;
                }
            } else {
                if (isLightTheme) {
                    themeId = R.style.ForceDarkAllowedFalse_Light;
                } else {
                    themeId = R.style.ForceDarkAllowedFalse_Dark;
                }
            }
            sContext.setTheme(themeId);
        });

        sInstrumentation.runOnMainSync(() -> {