Firefox · Core
CVE-2025-11720
Logic Error in Core
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt |
modified |
Files Changed
mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/ColorUtils.ktmobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.ktmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.ktmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.ktmobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarIntegration.ktmobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.ktmobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/ThemeUtils.ktmobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/ThemeUtilsTest.kt
Patch
diff --git a/mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/ColorUtils.kt b/mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/ColorUtils.kt
index 963cba64e0d..8f2911b650f 100644
--- a/mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/ColorUtils.kt
+++ b/mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/ColorUtils.kt
@@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.Color as ComposeColor
*/
private const val LIGHT_GRAY_HEX = "#66FBFBFE"
private const val DARK_GRAY_HEX = "#6615141A"
+private const val SECONDARY_COLOR_BACKGROUND_BLEND_RATIO = 0.25f
object ColorUtils {
@@ -24,15 +25,24 @@ object ColorUtils {
* Get text color (white or black) that is readable on top of the provided background color.
*/
@JvmStatic
- fun getReadableTextColor(@ColorInt backgroundColor: Int): Int {
+ @ColorInt fun getReadableTextColor(@ColorInt backgroundColor: Int): Int {
return if (isDark(backgroundColor)) Color.WHITE else Color.BLACK
}
+ /**
+ * Get secondary color (light or dark) that is readable on top of the provided background color.
+ */
+ @JvmStatic
+ @ColorInt fun getSecondaryReadableTextColor(@ColorInt backgroundColor: Int): Int {
+ val primaryTextColor = getReadableTextColor(backgroundColor)
+ return ColorUtils.blendARGB(primaryTextColor, backgroundColor, SECONDARY_COLOR_BACKGROUND_BLEND_RATIO)
+ }
+
/**
* Get disabled text color (light gray or dark gray) that is readable on top of the provided background color.
*/
@JvmStatic
- fun getDisabledReadableTextColor(@ColorInt backgroundColor: Int): Int {
+ @ColorInt fun getDisabledReadableTextColor(@ColorInt backgroundColor: Int): Int {
return if (isDark(backgroundColor)) {
LIGHT_GRAY_HEX.toColorInt()
} else {
@@ -56,7 +66,7 @@ object ColorUtils {
}
@SuppressWarnings("MagicNumber")
- private fun grayscaleFromRGB(@ColorInt color: Int): Int {
+ @ColorInt private fun grayscaleFromRGB(@ColorInt color: Int): Int {
val red = Color.red(color)
val green = Color.green(color)
val blue = Color.blue(color)
diff --git a/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt b/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
index 680a08ac601..10a071a4e81 100644
--- a/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
+++ b/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
@@ -6,6 +6,7 @@ package mozilla.components.support.utils
import android.graphics.Color
import androidx.compose.ui.graphics.toArgb
+import androidx.core.graphics.ColorUtils.calculateContrast
import androidx.test.ext.junit.runners.AndroidJUnit4
import mozilla.components.support.utils.ColorUtils.calculateAlphaFromPercentage
import mozilla.components.support.utils.ColorUtils.darken
@@ -41,6 +42,15 @@ class ColorUtilsTest {
assertEquals(Color.WHITE.toLong(), ColorUtils.getReadableTextColor(-0xa8400).toLong())
}
+ @Test
+ fun `getSecondaryReadableTextColor has a good contrast with the background color`() {
+ listOf(Color.GRAY, Color.CYAN, Color.YELLOW).forEach { backgroundColor ->
+ val secondaryReadableTextColor = ColorUtils.getSecondaryReadableTextColor(backgroundColor)
+ val contrast = calculateContrast(secondaryReadableTextColor, backgroundColor)
+ assertTrue(contrast > 2.5f)
+ }
+ }
+
@Test
fun isDark() {
assertTrue(ColorUtils.isDark(Color.BLACK))
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
index 08ec4a58241..f7406745785 100644
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt
@@ -21,6 +21,7 @@ import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.display.DisplayToolbar
import mozilla.components.concept.engine.utils.ABOUT_HOME_URL
import mozilla.components.concept.toolbar.ScrollableToolbar
+import mozilla.components.feature.customtabs.getConfiguredColorSchemeParams
import mozilla.components.support.ktx.util.URLStringUtils
import org.mozilla.fenix.R
import org.mozilla.fenix.components.toolbar.interactor.BrowserToolbarInteractor
@@ -30,6 +31,7 @@ import org.mozilla.fenix.ext.pixelSizeFor
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.ToolbarPopupWindow
+import org.mozilla.fenix.utils.getAppNightMode
import java.lang.ref.WeakReference
/**
@@ -158,6 +160,11 @@ class BrowserToolbarView(
}
toolbarIntegration = if (customTabSession != null) {
+ val colorSchemeParams = customTabSession.config.getConfiguredColorSchemeParams(
+ currentNightMode = context.resources.configuration.uiMode,
+ preferredNightMode = settings.getAppNightMode(),
+ )
+
CustomTabToolbarIntegration(
context = this,
toolbar = toolbar,
@@ -166,6 +173,7 @@ class BrowserToolbarView(
interactor = interactor,
customTabId = customTabSession.id,
isPrivate = customTabSession.content.private,
+ backgroundColor = colorSchemeParams?.toolbarColor,
)
} else {
DefaultToolbarIntegration(
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt
index 2f94eecead1..b89c673e0e5 100644
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt
@@ -5,6 +5,7 @@
package org.mozilla.fenix.components.toolbar
import android.content.Context
+import androidx.annotation.ColorInt
import androidx.annotation.VisibleForTesting
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
@@ -22,6 +23,8 @@ import mozilla.components.feature.toolbar.ToolbarPresenter
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.view.hideKeyboard
+import mozilla.components.support.utils.ColorUtils.getReadableTextColor
+import mozilla.components.support.utils.ColorUtils.getSecondaryReadableTextColor
import mozilla.components.ui.tabcounter.TabCounterMenu
import mozilla.telemetry.glean.private.NoExtras
import org.mozilla.fenix.GleanMetrics.AddressToolbar
@@ -46,6 +49,7 @@ abstract class ToolbarIntegration(
private val customTabId: String?,
isPrivate: Boolean,
renderStyle: ToolbarFeature.RenderStyle,
+ @param:ColorInt val backgroundColor: Int? = null,
) : LifecycleAwareFeature {
val store = context.components.core.store
@@ -56,8 +60,16 @@ abstract class ToolbarIntegration(
shouldDisplaySearchTerms = true,
urlRenderConfiguration = ToolbarFeature.UrlRenderConfiguration(
context.components.publicSuffixList,
- context.getColorFromAttr(R.attr.textPrimary),
- context.getColorFromAttr(R.attr.textSecondary),
+ if (backgroundColor != null && !isPrivate) {
+ getReadableTextColor(backgroundColor)
+ } else {
+ context.getColorFromAttr(R.attr.textPrimary)
+ },
+ if (backgroundColor != null && !isPrivate) {
+ getSecondaryReadableTextColor(backgroundColor)
+ } else {
+ context.getColorFromAttr(R.attr.textSecondary)
+ },
renderStyle = renderStyle,
),
)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarIntegration.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarIntegration.kt
index 8444e329f09..383202a8ec8 100644
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarIntegration.kt
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarIntegration.kt
@@ -5,6 +5,7 @@
package org.mozilla.fenix.customtabs
import android.content.Context
+import androidx.annotation.ColorInt
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.toolbar.ScrollableToolbar
import mozilla.components.feature.toolbar.ToolbarFeature
@@ -21,6 +22,7 @@ class CustomTabToolbarIntegration(
interactor: BrowserToolbarInteractor,
customTabId: String,
isPrivate: Boolean,
+ @ColorInt backgroundColor: Int? = null,
) : ToolbarIntegration(
context = context,
toolbar = toolbar,
@@ -30,4 +32,5 @@ class CustomTabToolbarIntegration(
customTabId = customTabId,
isPrivate = isPrivate,
renderStyle = ToolbarFeature.RenderStyle.ColoredDomain,
+ backgroundColor = backgroundColor,
)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt
index 1268556fa7d..bba065b6565 100644
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt
@@ -8,9 +8,6 @@ import android.app.Activity
import android.content.Context
import androidx.annotation.ColorInt
import androidx.annotation.VisibleForTesting
-import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
-import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt b/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
index 680a08ac601..10a071a4e81 100644
--- a/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
+++ b/mobile/android/android-components/components/support/utils/src/test/java/mozilla/components/support/utils/ColorUtilsTest.kt
@@ -6,6 +6,7 @@ package mozilla.components.support.utils
import android.graphics.Color
import androidx.compose.ui.graphics.toArgb
+import androidx.core.graphics.ColorUtils.calculateContrast
import androidx.test.ext.junit.runners.AndroidJUnit4
import mozilla.components.support.utils.ColorUtils.calculateAlphaFromPercentage
import mozilla.components.support.utils.ColorUtils.darken
@@ -41,6 +42,15 @@ class ColorUtilsTest {
assertEquals(Color.WHITE.toLong(), ColorUtils.getReadableTextColor(-0xa8400).toLong())
}
+ @Test
+ fun `getSecondaryReadableTextColor has a good contrast with the background color`() {
+ listOf(Color.GRAY, Color.CYAN, Color.YELLOW).forEach { backgroundColor ->
+ val secondaryReadableTextColor = ColorUtils.getSecondaryReadableTextColor(backgroundColor)
+ val contrast = calculateContrast(secondaryReadableTextColor, backgroundColor)
+ assertTrue(contrast > 2.5f)
+ }
+ }
+
@Test
fun isDark() {
assertTrue(ColorUtils.isDark(Color.BLACK))
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/ThemeUtilsTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/ThemeUtilsTest.kt
new file mode 100644
index 00000000000..7f60d0bd15d
--- /dev/null
+++ b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/ThemeUtilsTest.kt
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.utils
+
+import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
+import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
+import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import mozilla.components.support.test.mock
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.doReturn
+
+@RunWith(AndroidJUnit4::class)
+class ThemeUtilsTest {
+
+ @Test
+ fun `getAppNightMode returns MODE_NIGHT_FOLLOW_SYSTEM when shouldFollowDeviceTheme is true`() {
+ val settings = mock<Settings>()
+ doReturn(true).`when`(settings).shouldFollowDeviceTheme
+ assertEquals(MODE_NIGHT_FOLLOW_SYSTEM, settings.getAppNightMode())
+ }
+
+ @Test
+ fun `getAppNightMode returns MODE_NIGHT_NO when shouldFollowDeviceTheme is false and shouldUseLightTheme is true`() {
+ val settings = mock<Settings>()
+ doReturn(false).`when`(settings).shouldFollowDeviceTheme
+ doReturn(true).`when`(settings).shouldUseLightTheme
+ assertEquals(MODE_NIGHT_NO, settings.getAppNightMode())
+ }
+
+ @Test
+ fun `getAppNightMode returns MODE_NIGHT_YES when shouldFollowDeviceTheme is false and shouldUseLightTheme is false`() {
+ val settings = mock<Settings>()
+ doReturn(false).`when`(settings).shouldFollowDeviceTheme
+ doReturn(false).`when`(settings).shouldUseLightTheme
+ assertEquals(MODE_NIGHT_YES, settings.getAppNightMode())
+ }
+}
Loading diff…
References
On This Page