Skip to content

Commit 36bc6d0

Browse files
kdrag0nNRanjan-17
authored andcommitted
graphics: Override system fonts with user-selected overlays
Only using user-selected fonts for a subset of system apps leads to an inconsistent visual experience. While we've already applied them to the system's Material UI themes, many apps have hard-code references to sans-serif (whether it's through XML styles or Typeface.SANS_SERIF), so it is also necessary to override Typeface fonts at runtime. Changing overlays causes OverlayManagerService to schedule ApplicationInfo updates for affected apps, which forces a configuration change by incrementing Configuration#assetsSeq. TODO: figure out why not all apps get consistent configuration updates until manually relaunching activities Change-Id: I684a56315808f78f24a14cd6efeda0ea05e25abf Signed-off-by: Chiranth A J <chiranth@m.ms.evolution-x.org> Signed-off-by: aswin7469 <aswinas@pixysos.com> Signed-off-by: Abhinav Kumar <abhinav.115260@gmail.com>
1 parent 5e3aa6b commit 36bc6d0

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

core/java/android/app/ConfigurationController.java

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
import android.content.res.Resources;
3030
import android.graphics.Bitmap;
3131
import android.graphics.HardwareRenderer;
32+
import android.graphics.Typeface;
33+
import android.inputmethodservice.InputMethodService;
34+
import android.os.Build;
3235
import android.os.LocaleList;
3336
import android.os.Trace;
3437
import android.util.DisplayMetrics;
@@ -198,6 +201,7 @@ private void handleConfigurationChangedInner(@Nullable Configuration config,
198201

199202
final Application app = mActivityThread.getApplication();
200203
final Resources appResources = app.getResources();
204+
Typeface.updateDefaultFont(appResources);
201205
mResourcesManager.applyConfigurationToResources(config, compat);
202206
updateLocaleListFromAppContext(app.getApplicationContext());
203207

core/res/res/values/droidx_symbols.xml

+3
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@
1414
<java-symbol type="string" name="config_lightFontFamily" />
1515
<java-symbol type="string" name="config_regularFontFamily" />
1616

17+
<!-- For dynamic default font styles -->
18+
<java-symbol type="string" name="config_bodyFontFamily" />
19+
1720
</resources>

graphics/java/android/graphics/Typeface.java

+67-7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import android.annotation.UiThread;
3030
import android.compat.annotation.UnsupportedAppUsage;
3131
import android.content.res.AssetManager;
32+
import android.content.res.Resources;
3233
import android.graphics.fonts.Font;
3334
import android.graphics.fonts.FontFamily;
3435
import android.graphics.fonts.FontStyle;
@@ -70,12 +71,14 @@
7071
import java.io.InputStream;
7172
import java.lang.annotation.Retention;
7273
import java.lang.annotation.RetentionPolicy;
74+
import java.lang.reflect.Field;
7375
import java.nio.ByteBuffer;
7476
import java.nio.ByteOrder;
7577
import java.util.ArrayList;
7678
import java.util.Arrays;
7779
import java.util.Collections;
7880
import java.util.Comparator;
81+
import java.util.HashMap;
7982
import java.util.List;
8083
import java.util.Map;
8184
import java.util.Objects;
@@ -145,6 +148,9 @@ public class Typeface {
145148
private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
146149
private static final Object sDynamicCacheLock = new Object();
147150

151+
// For dynamic default font styles
152+
private static final HashMap<String, Typeface> sSystemFontOverrides = new HashMap<>();
153+
148154
private static final LruCache<Long, LruCache<String, Typeface>> sVariableCache =
149155
new LruCache<>(16);
150156
private static final Object sVariableCacheLock = new Object();
@@ -929,7 +935,7 @@ public CustomFallbackBuilder(@NonNull FontFamily family) {
929935
* @return The best matching typeface.
930936
*/
931937
public static Typeface create(String familyName, @Style int style) {
932-
return create(getSystemDefaultTypeface(familyName), style);
938+
return create(getSystemOverrideTypeface(familyName), style);
933939
}
934940

935941
/**
@@ -1296,6 +1302,11 @@ public void releaseNativeObjectForTest() {
12961302
mCleaner.run();
12971303
}
12981304

1305+
private static Typeface getSystemOverrideTypeface(@NonNull String familyName) {
1306+
Typeface tf = sSystemFontOverrides.get(familyName);
1307+
return tf == null ? getSystemDefaultTypeface(familyName) : tf;
1308+
}
1309+
12991310
private static Typeface getSystemDefaultTypeface(@NonNull String familyName) {
13001311
Typeface tf = sSystemFontMap.get(familyName);
13011312
return tf == null ? Typeface.DEFAULT : tf;
@@ -1477,6 +1488,60 @@ public static void setSystemFontMap(@Nullable SharedMemory sharedMemory)
14771488
}
14781489
}
14791490

1491+
private static void setPublicDefaults(String familyName) {
1492+
synchronized (SYSTEM_FONT_MAP_LOCK) {
1493+
sDefaults = new Typeface[] {
1494+
DEFAULT,
1495+
DEFAULT_BOLD,
1496+
create(getSystemDefaultTypeface(familyName), Typeface.ITALIC),
1497+
create(getSystemDefaultTypeface(familyName), Typeface.BOLD_ITALIC),
1498+
};
1499+
}
1500+
}
1501+
1502+
private static void setFinalField(String fieldName, Typeface value) {
1503+
synchronized (SYSTEM_FONT_MAP_LOCK) {
1504+
try {
1505+
Field field = Typeface.class.getDeclaredField(fieldName);
1506+
// isAccessible bypasses final on ART
1507+
field.setAccessible(true);
1508+
field.set(null, value);
1509+
field.setAccessible(false);
1510+
} catch (NoSuchFieldException | IllegalAccessException e) {
1511+
Log.e(TAG, "Failed to set Typeface." + fieldName, e);
1512+
}
1513+
}
1514+
}
1515+
1516+
/** @hide */
1517+
public static void updateDefaultFont(Resources res) {
1518+
synchronized (SYSTEM_FONT_MAP_LOCK) {
1519+
String familyName = res.getString(com.android.internal.R.string.config_bodyFontFamily);
1520+
Typeface typeface = sSystemFontMap.get(familyName);
1521+
if (typeface == null) {
1522+
// This should never happen, but if the system font family name is invalid, just return
1523+
// instead of crashing the app.
1524+
return;
1525+
}
1526+
1527+
setDefault(typeface);
1528+
1529+
// Static typefaces in public API
1530+
setFinalField("DEFAULT", create(getSystemDefaultTypeface(familyName), 0));
1531+
setFinalField("DEFAULT_BOLD", create(getSystemDefaultTypeface(familyName), Typeface.BOLD));
1532+
setFinalField("SANS_SERIF", DEFAULT);
1533+
1534+
// For default aliases used in framework styles
1535+
sSystemFontOverrides.put("sans-serif", typeface);
1536+
sSystemFontOverrides.put("sans-serif-thin", create(typeface, 100, false));
1537+
sSystemFontOverrides.put("sans-serif-light", create(typeface, 300, false));
1538+
sSystemFontOverrides.put("sans-serif-medium", create(typeface, 500, false));
1539+
sSystemFontOverrides.put("sans-serif-black", create(typeface, 900, false));
1540+
1541+
setPublicDefaults(familyName);
1542+
}
1543+
}
1544+
14801545
/** @hide */
14811546
@VisibleForTesting
14821547
public static void setSystemFontMap(Map<String, Typeface> systemFontMap) {
@@ -1497,12 +1562,7 @@ public static void setSystemFontMap(Map<String, Typeface> systemFontMap) {
14971562
nativeForceSetStaticFinalField("SERIF", create("serif", 0));
14981563
nativeForceSetStaticFinalField("MONOSPACE", create("monospace", 0));
14991564

1500-
sDefaults = new Typeface[]{
1501-
DEFAULT,
1502-
DEFAULT_BOLD,
1503-
create((String) null, Typeface.ITALIC),
1504-
create((String) null, Typeface.BOLD_ITALIC),
1505-
};
1565+
setPublicDefaults(null);
15061566

15071567
// A list of generic families to be registered in native.
15081568
// https://www.w3.org/TR/css-fonts-4/#generic-font-families

0 commit comments

Comments
 (0)