summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ViewRootImpl.java19
-rw-r--r--core/java/com/android/internal/util/ContrastColorUtil.java9
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java141
3 files changed, 119 insertions, 50 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4e3ff9063179..ec9f1cf8afd6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -189,6 +189,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RenderNode;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.hardware.SyncFence;
@@ -292,6 +293,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
@@ -2078,12 +2080,21 @@ public final class ViewRootImpl implements ViewParent,
// preference for dark mode in configuration.uiMode. Instead, we assume that both
// force invert and the system's dark theme are enabled.
if (shouldApplyForceInvertDark()) {
- final boolean isLightTheme =
- a.getBoolean(R.styleable.Theme_isLightTheme, false);
- // TODO: b/372558459 - Also check the background ColorDrawable color lightness
// TODO: b/368725782 - Use hwui color area detection instead of / in
// addition to these heuristics.
- if (isLightTheme) {
+ final boolean isLightTheme =
+ a.getBoolean(R.styleable.Theme_isLightTheme, false);
+ final boolean isBackgroundColorLight;
+ if (mView != null && mView.getBackground()
+ instanceof ColorDrawable colorDrawable) {
+ isBackgroundColorLight =
+ !ContrastColorUtil.isColorDarkLab(colorDrawable.getColor());
+ } else {
+ // Treat unknown as light, so that only isLightTheme is used to determine
+ // force dark treatment.
+ isBackgroundColorLight = true;
+ }
+ if (isLightTheme && isBackgroundColorLight) {
return ForceDarkType.FORCE_INVERT_COLOR_DARK;
} else {
return ForceDarkType.NONE;
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 0fd139188665..c68f107951ac 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -41,8 +41,6 @@ import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.Pair;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.util.Arrays;
import java.util.WeakHashMap;
@@ -381,6 +379,13 @@ public class ContrastColorUtil {
return calculateLuminance(color) <= 0.17912878474;
}
+ /** Like {@link #isColorDark(int)} but converts to LAB before checking the L component. */
+ public static boolean isColorDarkLab(int color) {
+ final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
+ ColorUtilsFromCompat.colorToLAB(color, result);
+ return result[0] < 50;
+ }
+
private int processColor(int color) {
return Color.argb(Color.alpha(color),
255 - Color.red(color),
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 5774109e1451..1b7805c351db 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.app.UiModeManager.MODE_NIGHT_NO;
-import static android.app.UiModeManager.MODE_NIGHT_YES;
import static android.util.SequenceUtils.getInitSeq;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
import static android.view.InputDevice.SOURCE_ROTARY_ENCODER;
@@ -69,10 +67,9 @@ import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
import android.app.Instrumentation;
import android.app.UiModeManager;
-import android.app.UiModeManager.ForceInvertType;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.ForceDarkType;
-import android.graphics.ForceDarkType.ForceDarkTypeDef;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
@@ -101,8 +98,6 @@ import com.android.compatibility.common.util.TestUtils;
import com.android.cts.input.BlockingQueueEventVerifier;
import com.android.window.flags.Flags;
-import com.google.common.truth.Expect;
-
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.AfterClass;
@@ -131,8 +126,6 @@ public class ViewRootImplTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Rule
- public final Expect mExpect = Expect.create();
private ViewRootImpl mViewRootImpl;
private View mView;
@@ -1516,29 +1509,83 @@ public class ViewRootImplTest {
}
@Test
- @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR)
- public void updateConfiguration_returnsExpectedForceDarkMode() {
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void determineForceDarkType_systemLightMode_returnsNone() throws Exception {
+ waitForSystemNightModeActivated(false);
+
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
+
+ }
+
+ @Test
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void determineForceDarkType_systemNightModeAndDisableForceInvertColor_returnsNone()
+ throws Exception {
waitForSystemNightModeActivated(true);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
+ enableForceInvertColor(false);
- waitForSystemNightModeActivated(false);
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
+ }
+
+ @Test
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void
+ determineForceDarkType_isLightThemeAndIsLightBackground_returnsForceInvertColorDark()
+ throws Exception {
+ // Set up configurations for force invert color
+ waitForSystemNightModeActivated(true);
+ enableForceInvertColor(true);
+
+ setUpViewAttributes(/* isLightTheme= */ true, /* isLightBackground = */ true);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
- verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false,
- UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE);
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType()
+ == ForceDarkType.FORCE_INVERT_COLOR_DARK));
+ }
+
+ @Test
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void determineForceDarkType_isLightThemeAndNotLightBackground_returnsNone()
+ throws Exception {
+ // Set up configurations for force invert color
+ waitForSystemNightModeActivated(true);
+ enableForceInvertColor(true);
+
+ setUpViewAttributes(/* isLightTheme= */ true, /* isLightBackground = */ false);
+
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
+ }
+
+ @Test
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void determineForceDarkType_notLightThemeAndIsLightBackground_returnsNone()
+ throws Exception {
+ // Set up configurations for force invert color
+ waitForSystemNightModeActivated(true);
+ enableForceInvertColor(true);
+
+ setUpViewAttributes(/* isLightTheme= */ false, /* isLightBackground = */ true);
+
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
+ }
+
+ @Test
+ @EnableFlags(FLAG_FORCE_INVERT_COLOR)
+ public void determineForceDarkType_notLightThemeAndNotLightBackground_returnsNone()
+ throws Exception {
+ // Set up configurations for force invert color
+ waitForSystemNightModeActivated(true);
+ enableForceInvertColor(true);
+
+ setUpViewAttributes(/* isLightTheme= */ false, /* isLightBackground = */ false);
+
+ TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
+ () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
}
@Test
@@ -1792,29 +1839,35 @@ public class ViewRootImplTest {
sInstrumentation.waitForIdleSync();
}
- private void verifyForceDarkType(boolean isAppInNightMode, boolean isForceInvertEnabled,
- @ForceInvertType int expectedForceInvertType,
- @ForceDarkTypeDef int expectedForceDarkType) {
- var uiModeManager = sContext.getSystemService(UiModeManager.class);
+ private void enableForceInvertColor(boolean enabled) {
ShellIdentityUtils.invokeWithShellPermissions(() -> {
- uiModeManager.setApplicationNightMode(
- isAppInNightMode ? MODE_NIGHT_YES : MODE_NIGHT_NO);
Settings.Secure.putInt(
sContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
- isForceInvertEnabled ? 1 : 0);
+ enabled ? 1 : 0
+ );
});
+ }
- sInstrumentation.runOnMainSync(() ->
- mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()));
- try {
- TestUtils.waitUntil("Waiting for force invert state changed",
- () -> (uiModeManager.getForceInvertState() == expectedForceInvertType));
- } catch (Exception e) {
- Log.e(TAG, "Unexpected error trying to apply force invert state. " + e);
- e.printStackTrace();
- }
+ private void setUpViewAttributes(boolean isLightTheme, boolean isLightBackground) {
+ ShellIdentityUtils.invokeWithShellPermissions(() -> {
+ sContext.setTheme(isLightTheme ? android.R.style.Theme_DeviceDefault_Light
+ : android.R.style.Theme_DeviceDefault);
+ });
- mExpect.that(mViewRootImpl.determineForceDarkType()).isEqualTo(expectedForceDarkType);
+ sInstrumentation.runOnMainSync(() -> {
+ View view = new View(sContext);
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ TYPE_APPLICATION_OVERLAY);
+ layoutParams.token = new Binder();
+ view.setLayoutParams(layoutParams);
+ if (isLightBackground) {
+ view.setBackgroundColor(Color.WHITE);
+ } else {
+ view.setBackgroundColor(Color.BLACK);
+ }
+ mViewRootImpl.setView(view, layoutParams, /* panelParentView= */ null);
+ mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId());
+ });
}
}