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

Commit 039756dc authored by Chaohui Wang's avatar Chaohui Wang
Browse files

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
parent 597fe60d
Loading
Loading
Loading
Loading
+26 −20
Original line number Diff line number Diff line
@@ -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)
}
+1 −0
Original line number Diff line number Diff line
@@ -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"],
+5 −4
Original line number Diff line number Diff line
@@ -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"
}
+104 −0
Original line number Diff line number Diff line
/*
 * 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
    }
}