[Font] Try-catch ResourceCompat.getFont
Fallback on using "sans-serif" when font res failed. Add an UMA "Android.StyleUtils.FontLoadingOutcome" to capture fallback cases. Bug: 410715278 Change-Id: I97abb867dadfdb5bf081af775a581741e9d89ffe Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6496508 Commit-Queue: Wenyu Fu <wenyufu@chromium.org> Reviewed-by: Sinan Sahin <sinansahin@google.com> Cr-Commit-Position: refs/heads/main@{#1454035}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
3b75e15924
commit
685d64a1f0
tools/metrics/histograms/metadata/android
ui/android
@ -993,6 +993,12 @@ chromium-metrics-reviews@google.com.
|
||||
<int value="8" label="Undefined"/>
|
||||
</enum>
|
||||
|
||||
<enum name="FontLoadingOutcome">
|
||||
<int value="0" label="Fallback Font Family"/>
|
||||
<int value="1" label="Font resource"/>
|
||||
<int value="2" label="Font family"/>
|
||||
</enum>
|
||||
|
||||
<enum name="FrameJankStatus">
|
||||
<int value="0" label="Janky"/>
|
||||
<int value="1" label="NonJanky"/>
|
||||
|
@ -4945,6 +4945,16 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Android.StyleUtils.FontLoadingOutcome"
|
||||
enum="FontLoadingOutcome" expires_after="2025-11-28">
|
||||
<owner>wenyufu@chromium.org</owner>
|
||||
<owner>clank-app-team@google.com</owner>
|
||||
<summary>
|
||||
Records the outcome for loading font using applyTextAppearanceToTextPaint.
|
||||
Recorded during layout initialization on tablets.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Android.Survey.DownloadRequested2" enum="BooleanRequested"
|
||||
expires_after="2025-10-19">
|
||||
<owner>wenyufu@chromium.org</owner>
|
||||
|
@ -5,22 +5,47 @@
|
||||
package org.chromium.ui.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextPaint;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.annotation.StyleableRes;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import org.chromium.base.Log;
|
||||
import org.chromium.base.metrics.RecordHistogram;
|
||||
import org.chromium.build.annotations.NullMarked;
|
||||
import org.chromium.ui.R;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/** Helper functions for working with styles. */
|
||||
@NullMarked
|
||||
public class StyleUtils {
|
||||
private static final String TAG = "StyleUtils";
|
||||
private static final int INVALID_RESOURCE_ID = -1;
|
||||
private static final String FALLBACK_FONT_FAMILY_NAME = "sans-serif";
|
||||
|
||||
// These values are persisted to logs. Entries should not be renumbered and
|
||||
// numeric values should never be reused.
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
FontLoadingOutcome.FALLBACK_FONT_FAMILY,
|
||||
FontLoadingOutcome.FONT_RES,
|
||||
FontLoadingOutcome.FONT_FAMILY,
|
||||
FontLoadingOutcome.NUM_TOTAL
|
||||
})
|
||||
@interface FontLoadingOutcome {
|
||||
int FALLBACK_FONT_FAMILY = 0;
|
||||
int FONT_RES = 1;
|
||||
int FONT_FAMILY = 2;
|
||||
|
||||
int NUM_TOTAL = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies attributes extracted from a TextAppearance style to a TextPaint object.
|
||||
@ -45,17 +70,28 @@ public class StyleUtils {
|
||||
context.getTheme().obtainStyledAttributes(style, R.styleable.TextAppearance);
|
||||
|
||||
Typeface typeface;
|
||||
@FontLoadingOutcome int outcome;
|
||||
if (applyFontFamily) {
|
||||
@StyleableRes int fontStyleableRes = R.styleable.TextAppearance_android_fontFamily;
|
||||
int fontRes = appearance.getResourceId(fontStyleableRes, INVALID_RESOURCE_ID);
|
||||
if (fontRes != INVALID_RESOURCE_ID) {
|
||||
typeface = ResourcesCompat.getFont(context, fontRes);
|
||||
try {
|
||||
typeface = ResourcesCompat.getFont(context, fontRes);
|
||||
outcome = FontLoadingOutcome.FONT_RES;
|
||||
} catch (NotFoundException e) {
|
||||
Log.e(TAG, "Reading fontRes failed.", e);
|
||||
typeface = Typeface.create(FALLBACK_FONT_FAMILY_NAME, Typeface.NORMAL);
|
||||
outcome = FontLoadingOutcome.FALLBACK_FONT_FAMILY;
|
||||
}
|
||||
} else {
|
||||
String fontFamily = appearance.getString(fontStyleableRes);
|
||||
typeface = Typeface.create(fontFamily, Typeface.NORMAL);
|
||||
outcome = FontLoadingOutcome.FONT_FAMILY;
|
||||
}
|
||||
|
||||
textPaint.setTypeface(typeface);
|
||||
RecordHistogram.recordEnumeratedHistogram(
|
||||
"Android.StyleUtils.FontLoadingOutcome", outcome, FontLoadingOutcome.NUM_TOTAL);
|
||||
}
|
||||
|
||||
if (applyTextSize) {
|
||||
|
@ -18,7 +18,9 @@ import org.junit.runner.RunWith;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import org.chromium.base.test.BaseRobolectricTestRunner;
|
||||
import org.chromium.base.test.util.HistogramWatcher;
|
||||
import org.chromium.ui.R;
|
||||
import org.chromium.ui.util.StyleUtils.FontLoadingOutcome;
|
||||
|
||||
/** Tests for {@link StyleUtils} class. */
|
||||
@RunWith(BaseRobolectricTestRunner.class)
|
||||
@ -33,6 +35,9 @@ public class StyleUtilsTest {
|
||||
|
||||
@Test
|
||||
public void applyTextAppearanceToTextPaint_StringFontFamily() {
|
||||
var watcher =
|
||||
HistogramWatcher.newSingleRecordWatcher(
|
||||
"Android.StyleUtils.FontLoadingOutcome", FontLoadingOutcome.FONT_FAMILY);
|
||||
TextPaint textPaint = new TextPaint();
|
||||
// Should not crash if font-family resource is not found, string font family will be
|
||||
// constructed instead.
|
||||
@ -44,10 +49,14 @@ public class StyleUtilsTest {
|
||||
/* applyFontFamily= */ true,
|
||||
/* applyTextSize= */ false,
|
||||
/* applyTextColor= */ false);
|
||||
watcher.assertExpected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyTextAppearanceToTextPaint_CustomFontSizeText() {
|
||||
var watcher =
|
||||
HistogramWatcher.newSingleRecordWatcher(
|
||||
"Android.StyleUtils.FontLoadingOutcome", FontLoadingOutcome.FONT_RES);
|
||||
TextPaint textPaint = new TextPaint();
|
||||
StyleUtils.applyTextAppearanceToTextPaint(
|
||||
mContext,
|
||||
@ -56,6 +65,7 @@ public class StyleUtilsTest {
|
||||
/* applyFontFamily= */ true,
|
||||
/* applyTextSize= */ true,
|
||||
/* applyTextColor= */ true);
|
||||
watcher.assertExpected();
|
||||
// Verify test values defined in resources.
|
||||
assertEquals(
|
||||
"Applied font is incorrect.",
|
||||
|
Reference in New Issue
Block a user