Fix SettingsFontFamily when config is empty

Some device or when Compose preview, the font config is empty.

Use the default font family when the config is empty to fix.

Bug: 235727273
Test: Unit test
Test: Manual with Gallery App
Change-Id: Ifd9c5bbc3d446e5fdb5f393ad994c7545656ead6
This commit is contained in:
Chaohui Wang
2022-11-02 13:40:44 +08:00
parent 597fe60dbe
commit 039756dc93
4 changed files with 136 additions and 24 deletions

View File

@@ -21,45 +21,51 @@ package com.android.settingslib.spa.framework.theme
import android.annotation.SuppressLint
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.DeviceFontFamilyName
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import com.android.settingslib.spa.framework.compose.rememberContext
internal data class SettingsFontFamily(
val brand: FontFamily = FontFamily.Default,
val plain: FontFamily = FontFamily.Default,
val brand: FontFamily,
val plain: FontFamily,
)
private fun Context.getSettingsFontFamily(inInspection: Boolean): SettingsFontFamily {
if (inInspection) {
return SettingsFontFamily()
}
private fun Context.getSettingsFontFamily(): SettingsFontFamily {
return SettingsFontFamily(
brand = FontFamily(
Font(getFontFamilyName("config_headlineFontFamily"), FontWeight.Normal),
Font(getFontFamilyName("config_headlineFontFamilyMedium"), FontWeight.Medium),
brand = getFontFamily(
configFontFamilyNormal = "config_headlineFontFamily",
configFontFamilyMedium = "config_headlineFontFamilyMedium",
),
plain = FontFamily(
Font(getFontFamilyName("config_bodyFontFamily"), FontWeight.Normal),
Font(getFontFamilyName("config_bodyFontFamilyMedium"), FontWeight.Medium),
plain = getFontFamily(
configFontFamilyNormal = "config_bodyFontFamily",
configFontFamilyMedium = "config_bodyFontFamilyMedium",
),
)
}
private fun Context.getFontFamilyName(configName: String): DeviceFontFamilyName {
private fun Context.getFontFamily(
configFontFamilyNormal: String,
configFontFamilyMedium: String,
): FontFamily {
val fontFamilyNormal = getAndroidConfig(configFontFamilyNormal)
val fontFamilyMedium = getAndroidConfig(configFontFamilyMedium)
if (fontFamilyNormal.isEmpty() || fontFamilyMedium.isEmpty()) return FontFamily.Default
return FontFamily(
Font(DeviceFontFamilyName(fontFamilyNormal), FontWeight.Normal),
Font(DeviceFontFamilyName(fontFamilyMedium), FontWeight.Medium),
)
}
private fun Context.getAndroidConfig(configName: String): String {
@SuppressLint("DiscouragedApi")
val configId = resources.getIdentifier(configName, "string", "android")
return DeviceFontFamilyName(resources.getString(configId))
return resources.getString(configId)
}
@Composable
internal fun rememberSettingsFontFamily(): SettingsFontFamily {
val context = LocalContext.current
val inInspection = LocalInspectionMode.current
return remember { context.getSettingsFontFamily(inInspection) }
return rememberContext(Context::getSettingsFontFamily)
}

View File

@@ -31,6 +31,7 @@ android_test {
"androidx.compose.runtime_runtime",
"androidx.compose.ui_ui-test-junit4",
"androidx.compose.ui_ui-test-manifest",
"mockito-target-minus-junit4",
"truth-prebuilt",
],
kotlincflags: ["-Xjvm-default=all"],

View File

@@ -58,9 +58,10 @@ android {
}
dependencies {
androidTestImplementation(project(":spa"))
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$jetpack_compose_version")
androidTestImplementation 'com.google.truth:truth:1.1.3'
androidTestImplementation project(":spa")
androidTestImplementation "androidx.test.ext:junit-ktx:1.1.3"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$jetpack_compose_version"
androidTestImplementation "com.google.truth:truth:1.1.3"
androidTestImplementation "org.mockito:mockito-android:3.4.6"
androidTestDebugImplementation "androidx.compose.ui:ui-test-manifest:$jetpack_compose_version"
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settingslib.spa.framework.theme
import android.content.Context
import android.content.res.Resources
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Typography
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.text.font.FontFamily
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.anyInt
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
class SettingsThemeTest {
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@get:Rule
val composeTestRule = createComposeRule()
@Mock
private lateinit var context: Context
@Mock
private lateinit var resources: Resources
private var nextMockResId = 1
@Before
fun setUp() {
whenever(context.resources).thenReturn(resources)
whenever(resources.getString(anyInt())).thenReturn("")
}
private fun mockAndroidConfig(configName: String, configValue: String) {
whenever(resources.getIdentifier(configName, "string", "android"))
.thenReturn(nextMockResId)
whenever(resources.getString(nextMockResId)).thenReturn(configValue)
nextMockResId++
}
@Test
fun noFontFamilyConfig_useDefaultFontFamily() {
val fontFamily = getFontFamily()
assertThat(fontFamily.headlineLarge.fontFamily).isSameInstanceAs(FontFamily.Default)
assertThat(fontFamily.bodyLarge.fontFamily).isSameInstanceAs(FontFamily.Default)
}
@Test
fun hasFontFamilyConfig_useConfiguredFontFamily() {
mockAndroidConfig("config_headlineFontFamily", "HeadlineNormal")
mockAndroidConfig("config_headlineFontFamilyMedium", "HeadlineMedium")
mockAndroidConfig("config_bodyFontFamily", "BodyNormal")
mockAndroidConfig("config_bodyFontFamilyMedium", "BodyMedium")
val fontFamily = getFontFamily()
val headlineFontFamily = fontFamily.headlineLarge.fontFamily.toString()
assertThat(headlineFontFamily).contains("HeadlineNormal")
assertThat(headlineFontFamily).contains("HeadlineMedium")
val bodyFontFamily = fontFamily.bodyLarge.fontFamily.toString()
assertThat(bodyFontFamily).contains("BodyNormal")
assertThat(bodyFontFamily).contains("BodyMedium")
}
private fun getFontFamily(): Typography {
lateinit var typography: Typography
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
SettingsTheme {
typography = MaterialTheme.typography
}
}
}
return typography
}
}