隨着Android(三星,LG,HTC)的一些口味,它看起來像是可能的set the default system font without rooting。我沒有這些設備來測試對一個(我有一個較舊的聯想平板電腦),但我想知道以下幾點:Android - 檢索默認系統字體字符串名稱
- 是否Typeface.DEFAULT方法返回定製的字樣這些設備上的字體還是始終返回Roboto的信息?
- 如果它確實返回自定義字體上的信息,如何以編程方式獲取自定義字體的字體名稱(字符串)?
- 如果Typeface.DEFAULT是一個死衚衕,有沒有另一種方法來獲取默認的系統字體名稱?也許是爲了TTF文件?
編輯:我添加的方式,我想可能會奏效,但在現實中並不:比較Typeface.DEFAULT到字體在/system/fonts
,/system/font
,並/data/fonts
目錄從文件中創建的對象。 這不是一個答案,但它可能有助於激勵某人想出一個答案。另請注意,TTFAnalyzer類是而不是地雷。代碼如下:
private String getDefaultFont() {
String[] fontdirs = { "/system/fonts", "/system/font", "/data/fonts" };
TTFAnalyzer analyzer = new TTFAnalyzer();
Typeface tfDefault = Typeface.DEFAULT;
Typeface tfTemp = null;
String defaultFontName = "";
System.out.println("getDefaultFont(): entry");
System.out.println("tfDefault: " + tfDefault.toString());
for (String fontdir : fontdirs)
{
File dir = new File(fontdir);
if (!dir.exists())
continue;
File[] files = dir.listFiles();
if (files == null)
continue;
for (File file : files)
{
String fontname = analyzer.getTtfFontName(file.getAbsolutePath());
if (fontname != null) {
System.out.println("found font: " + fontname);
tfTemp = Typeface.createFromFile(file);
System.out.println("tfTemp: " + tfTemp.toString());
//** THIS SHOULD BE WORKING? **//
if (tfTemp.equals(tfDefault)) {
System.out.println("Found default font: " + fontname);
defaultFontName = fontname;
}
}
}
}
return defaultFontName;
}
// The class which loads the TTF file, parses it and returns the TTF font name
class TTFAnalyzer
{
// This function parses the TTF file and returns the font name specified in the file
public String getTtfFontName(String fontFilename)
{
try
{
// Parses the TTF file format.
// See http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html
m_file = new RandomAccessFile(fontFilename, "r");
// Read the version first
int version = readDword();
// The version must be either 'true' (0x74727565) or 0x00010000
if (version != 0x74727565 && version != 0x00010000)
return null;
// The TTF file consist of several sections called "tables", and we need to know how many of them are there.
int numTables = readWord();
// Skip the rest in the header
readWord(); // skip searchRange
readWord(); // skip entrySelector
readWord(); // skip rangeShift
// Now we can read the tables
for (int i = 0; i < numTables; i++)
{
// Read the table entry
int tag = readDword();
readDword(); // skip checksum
int offset = readDword();
int length = readDword();
// Now here' the trick. 'name' field actually contains the textual string name.
// So the 'name' string in characters equals to 0x6E616D65
if (tag == 0x6E616D65)
{
// Here's the name section. Read it completely into the allocated buffer
byte[] table = new byte[ length ];
m_file.seek(offset);
read(table);
// This is also a table. See http://developer.apple.com/fonts/ttrefman/rm06/Chap6name.html
// According to Table 36, the total number of table records is stored in the second word, at the offset 2.
// Getting the count and string offset - remembering it's big endian.
int count = getWord(table, 2);
int string_offset = getWord(table, 4);
// Record starts from offset 6
for (int record = 0; record < count; record++)
{
// Table 37 tells us that each record is 6 words -> 12 bytes, and that the nameID is 4th word so its offset is 6.
// We also need to account for the first 6 bytes of the header above (Table 36), so...
int nameid_offset = record * 12 + 6;
int platformID = getWord(table, nameid_offset);
int nameid_value = getWord(table, nameid_offset + 6);
// Table 42 lists the valid name Identifiers. We're interested in 4 but not in Unicode encoding (for simplicity).
// The encoding is stored as PlatformID and we're interested in Mac encoding
if (nameid_value == 4 && platformID == 1)
{
// We need the string offset and length, which are the word 6 and 5 respectively
int name_length = getWord(table, nameid_offset + 8);
int name_offset = getWord(table, nameid_offset + 10);
// The real name string offset is calculated by adding the string_offset
name_offset = name_offset + string_offset;
// Make sure it is inside the array
if (name_offset >= 0 && name_offset + name_length < table.length)
return new String(table, name_offset, name_length);
}
}
}
}
return null;
}
catch (FileNotFoundException e)
{
// Permissions?
return null;
}
catch (IOException e)
{
// Most likely a corrupted font file
return null;
}
}
// Font file; must be seekable
private RandomAccessFile m_file = null;
// Helper I/O functions
private int readByte() throws IOException
{
return m_file.read() & 0xFF;
}
private int readWord() throws IOException
{
int b1 = readByte();
int b2 = readByte();
return b1 << 8 | b2;
}
private int readDword() throws IOException
{
int b1 = readByte();
int b2 = readByte();
int b3 = readByte();
int b4 = readByte();
return b1 << 24 | b2 << 16 | b3 << 8 | b4;
}
private void read(byte [] array) throws IOException
{
if (m_file.read(array) != array.length)
throw new IOException();
}
// Helper
private int getWord(byte [] array, int offset)
{
int b1 = array[ offset ] & 0xFF;
int b2 = array[ offset + 1 ] & 0xFF;
return b1 << 8 | b2;
}
}
編輯2:從我的聯想平板打交道了一些更多的信息。在/system/etc
,有感興趣的一對夫婦的XML文件:
system_fonts.xml
- 這看起來有定期的默認字體/斜體/大膽作爲其第一家進入fallback_fonts.xml
- 其中有字體如果Android無法在當前字體中找到字形(例如,泰文字符),則應該使用Android。
這可能是值得解析通過該system_fonts並從那裏返回默認的字體名稱 - 但我不知道如果這是「正確」的方式來做到這一點。
望着Typeface'類的'源,它看起來像這只是一個存根,每個方法的代碼'拋出新的RuntimeException(「存根!」 )'。此外,常量(包括'DEFAULT')被設置爲'null'。因此'字體。DEFAULT'應該總是給你'空'。我不太明白這個班上的實際電話是如何工作的。 –
嗨阿列克斯 - 你從哪裏得到來源?我搜索了周圍,並可以找到https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/Typeface.java - 這似乎確實不僅僅是一個存根。不過,我不確定這是否是實際的源代碼庫。 : -/ – eb1
嗯,有趣......我在看一個較舊的版本,因爲這就是我所處的位置 - 我認爲它是4.3或甚至4.1 –