build/make/core/Makefile
# Set recovery_density to a density bucket based on TARGET_SCREEN_DENSITY, PRODUCT_AAPT_PREF_CONFIG,
# or mdpi, in order of preference. We support both specific buckets (e.g. xdpi) and numbers,
# which get remapped to a bucket.
recovery_density := $(or $(TARGET_SCREEN_DENSITY),$(PRODUCT_AAPT_PREF_CONFIG),mdpi)
ifeq (,$(filter xxxhdpi xxhdpi xhdpi hdpi mdpi,$(recovery_density)))
recovery_density_value := $(patsubst %dpi,%,$(recovery_density))
# We roughly use the medium point between the primary densities to split buckets.
# ------160------240------320----------480------------640------
# mdpi hdpi xhdpi xxhdpi xxxhdpi
recovery_density := $(strip \
$(or $(if $(filter $(shell echo $$(($(recovery_density_value) >= 560))),1),xxxhdpi),\
$(if $(filter $(shell echo $$(($(recovery_density_value) >= 400))),1),xxhdpi),\
$(if $(filter $(shell echo $$(($(recovery_density_value) >= 280))),1),xhdpi),\
$(if $(filter $(shell echo $$(($(recovery_density_value) >= 200))),1),hdpi,mdpi)))
endif
ifneq (,$(wildcard $(recovery_resources_common)-$(recovery_density)))
recovery_resources_common := $(recovery_resources_common)-$(recovery_density)
else
recovery_resources_common := $(recovery_resources_common)-xhdpi
endif
# Select the 18x32 font on high-density devices (xhdpi and up); and the 12x22 font on other devices.
# Note that the font selected here can be overridden for a particular device by putting a font.png
# in its private recovery resources.
ifneq (,$(filter xxxhdpi xxhdpi xhdpi,$(recovery_density)))
recovery_font := $(call include-path-for, recovery)/fonts/18x32.png
else
recovery_font := $(call include-path-for, recovery)/fonts/12x22.png
endif
# We will only generate the recovery background text images if the variable
# TARGET_RECOVERY_UI_SCREEN_WIDTH is defined. For devices with xxxhdpi and xxhdpi, we set the
# variable to the commonly used values here, if it hasn't been intialized elsewhere. While for
# devices with lower density, they must have TARGET_RECOVERY_UI_SCREEN_WIDTH defined in their
# BoardConfig in order to use this feature.
ifeq ($(recovery_density),xxxhdpi)
TARGET_RECOVERY_UI_SCREEN_WIDTH ?= 1440
else ifeq ($(recovery_density),xxhdpi)
TARGET_RECOVERY_UI_SCREEN_WIDTH ?= 1080
else ifeq ($(recovery_density),xhdpi)
TARGET_RECOVERY_UI_SCREEN_WIDTH ?= 720
else ifeq ($(recovery_density),hdpi)
TARGET_RECOVERY_UI_SCREEN_WIDTH ?= 480
endif
ifneq ($(TARGET_RECOVERY_UI_SCREEN_WIDTH),)
# Subtracts the margin width and menu indent from the screen width; it's safe to be conservative.
ifeq ($(TARGET_RECOVERY_UI_MARGIN_WIDTH),)
recovery_image_width := $$(($(TARGET_RECOVERY_UI_SCREEN_WIDTH) - 10))
else
recovery_image_width := $$(($(TARGET_RECOVERY_UI_SCREEN_WIDTH) - $(TARGET_RECOVERY_UI_MARGIN_WIDTH) - 10))
endif
RECOVERY_INSTALLING_TEXT_FILE := $(call intermediates-dir-for,PACKAGING,recovery_text_res)/installing_text.png
RECOVERY_INSTALLING_SECURITY_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/installing_security_text.png
RECOVERY_ERASING_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/erasing_text.png
RECOVERY_ERROR_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/error_text.png
RECOVERY_NO_COMMAND_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/no_command_text.png
RECOVERY_CANCEL_WIPE_DATA_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/cancel_wipe_data_text.png
RECOVERY_FACTORY_DATA_RESET_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/factory_data_reset_text.png
RECOVERY_TRY_AGAIN_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/try_again_text.png
RECOVERY_WIPE_DATA_CONFIRMATION_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/wipe_data_confirmation_text.png
RECOVERY_WIPE_DATA_MENU_HEADER_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/wipe_data_menu_header_text.png
generated_recovery_text_files := \
$(RECOVERY_INSTALLING_TEXT_FILE) \
$(RECOVERY_INSTALLING_SECURITY_TEXT_FILE) \
$(RECOVERY_ERASING_TEXT_FILE) \
$(RECOVERY_ERROR_TEXT_FILE) \
$(RECOVERY_NO_COMMAND_TEXT_FILE) \
$(RECOVERY_CANCEL_WIPE_DATA_TEXT_FILE) \
$(RECOVERY_FACTORY_DATA_RESET_TEXT_FILE) \
$(RECOVERY_TRY_AGAIN_TEXT_FILE) \
$(RECOVERY_WIPE_DATA_CONFIRMATION_TEXT_FILE) \
$(RECOVERY_WIPE_DATA_MENU_HEADER_TEXT_FILE)
resource_dir := $(call include-path-for, recovery)/tools/recovery_l10n/res/
image_generator_jar := $(HOST_OUT_JAVA_LIBRARIES)/RecoveryImageGenerator.jar
zopflipng := $(HOST_OUT_EXECUTABLES)/zopflipng
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_SOURCE_FONTS := $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_FONT_FILES_DIR := $(call intermediates-dir-for,PACKAGING,recovery_font_files)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RESOURCE_DIR := $(resource_dir)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_IMAGE_GENERATOR_JAR := $(image_generator_jar)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_ZOPFLIPNG := $(zopflipng)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_IMAGE_WIDTH := $(recovery_image_width)
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_BACKGROUND_TEXT_LIST := \
recovery_installing \
recovery_installing_security \
recovery_erasing \
recovery_error \
recovery_no_command
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_WIPE_DATA_TEXT_LIST := \
recovery_cancel_wipe_data \
recovery_factory_data_reset \
recovery_try_again \
recovery_wipe_data_menu_header \
recovery_wipe_data_confirmation
$(RECOVERY_INSTALLING_TEXT_FILE): .KATI_IMPLICIT_OUTPUTS := $(filter-out $(RECOVERY_INSTALLING_TEXT_FILE),$(generated_recovery_text_files))
$(RECOVERY_INSTALLING_TEXT_FILE): $(image_generator_jar) $(resource_dir) $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep) $(zopflipng)
# Prepares the font directory.
@rm -rf $(PRIVATE_RECOVERY_FONT_FILES_DIR)
@mkdir -p $(PRIVATE_RECOVERY_FONT_FILES_DIR)
$(foreach filename,$(PRIVATE_SOURCE_FONTS), cp $(filename) $(PRIVATE_RECOVERY_FONT_FILES_DIR) &&) true
@rm -rf $(dir $@)
@mkdir -p $(dir $@)
$(foreach text_name,$(PRIVATE_RECOVERY_BACKGROUND_TEXT_LIST) $(PRIVATE_RECOVERY_WIPE_DATA_TEXT_LIST), \
$(eval output_file := $(dir $@)/$(patsubst recovery_%,%_text.png,$(text_name))) \
$(eval center_alignment := $(if $(filter $(text_name),$(PRIVATE_RECOVERY_BACKGROUND_TEXT_LIST)), --center_alignment)) \
java -jar $(PRIVATE_IMAGE_GENERATOR_JAR) \
--image_width $(PRIVATE_RECOVERY_IMAGE_WIDTH) \
--text_name $(text_name) \
--font_dir $(PRIVATE_RECOVERY_FONT_FILES_DIR) \
--resource_dir $(PRIVATE_RESOURCE_DIR) \
--output_file $(output_file) $(center_alignment) && \
$(PRIVATE_ZOPFLIPNG) -y --iterations=1 --filters=0 $(output_file) $(output_file) > /dev/null &&) true
else
RECOVERY_INSTALLING_TEXT_FILE :=
RECOVERY_INSTALLING_SECURITY_TEXT_FILE :=
RECOVERY_ERASING_TEXT_FILE :=
RECOVERY_ERROR_TEXT_FILE :=
RECOVERY_NO_COMMAND_TEXT_FILE :=
RECOVERY_CANCEL_WIPE_DATA_TEXT_FILE :=
RECOVERY_FACTORY_DATA_RESET_TEXT_FILE :=
RECOVERY_TRY_AGAIN_TEXT_FILE :=
RECOVERY_WIPE_DATA_CONFIRMATION_TEXT_FILE :=
RECOVERY_WIPE_DATA_MENU_HEADER_TEXT_FILE :=
endif # TARGET_RECOVERY_UI_SCREEN_WIDTH
代码很多,其中最关键代码如下,是通过 jar 包去生成 recovery 字体图片的
java -jar $(PRIVATE_IMAGE_GENERATOR_JAR) \
--image_width $(PRIVATE_RECOVERY_IMAGE_WIDTH) \
--text_name $(text_name) \
--font_dir $(PRIVATE_RECOVERY_FONT_FILES_DIR) \
--resource_dir $(PRIVATE_RESOURCE_DIR) \
--output_file $(output_file) $(center_alignment)
第一个参数 PRIVATE_IMAGE_GENERATOR_JAR 指的是用于生成图片的jar包
PRIVATE_IMAGE_GENERATOR_JAR := $(image_generator_jar)
image_generator_jar := $(HOST_OUT_JAVA_LIBRARIES)/RecoveryImageGenerator.jar
在 out/host 下生成的 jar 包路径 out/host/linux-x86/framework/RecoveryImageGenerator.jar
查找 RecoveryImageGenerator 模块在源码中对应的路径
pathmod RecoveryImageGenerator
alps/bootable/recovery/tools/image_generator
这个目录下有一个 java 文件,bootable/recovery/tools/image_generator/ImageGenerator.java
关键的 main()
函数代码如下
public static void main(String[] args)
throws NumberFormatException, IOException, FontFormatException,
LocalizedStringNotFoundException {
Options options = createOptions();
CommandLine cmd;
try {
cmd = new GnuParser().parse(options, args);
} catch (ParseException e) {
System.err.println(e.getMessage());
printUsage(options);
return;
}
int imageWidth = Integer.parseUnsignedInt(cmd.getOptionValue("image_width"));
if (cmd.hasOption("verbose")) {
LOGGER.setLevel(Level.INFO);
} else {
LOGGER.setLevel(Level.WARNING);
}
ImageGenerator imageGenerator =
new ImageGenerator(
imageWidth,
cmd.getOptionValue("text_name"),
DEFAULT_FONT_SIZE,
cmd.getOptionValue("font_dir"),
cmd.hasOption("center_alignment"));
Set<String> localesSet = null;
if (cmd.hasOption("locales")) {
String[] localesList = cmd.getOptionValue("locales").split(",");
localesSet = new HashSet<>(Arrays.asList(localesList));
// Ensures that we have the default locale, all english translations are identical.
localesSet.add("en-rAU");
}
Map<Locale, String> localizedStringMap =
imageGenerator.readLocalizedStringFromXmls(cmd.getOptionValue("resource_dir"),
localesSet);
imageGenerator.generateImage(localizedStringMap, cmd.getOptionValue("output_file"));
}
构造函数
public ImageGenerator(
int initialImageWidth,
String textName,
float fontSize,
String fontDirPath,
boolean centerAlignment) {
mImageWidth = initialImageWidth;
mImageHeight = INITIAL_HEIGHT;
mVerticalOffset = 0;
// Initialize the canvas with the default height.
mBufferedImage = new BufferedImage(mImageWidth, mImageHeight, BufferedImage.TYPE_BYTE_GRAY);
mTextName = textName;
mFontSize = fontSize;
mFontDirPath = fontDirPath;
mLoadedFontMap = new TreeMap<>();
mCenterAlignment = centerAlignment;
}
其中几个参数
1.PRIVATE_RECOVERY_IMAGE_WIDTH 图片宽度
PRIVATE_RECOVERY_IMAGE_WIDTH := $(recovery_image_width)
recovery_image_width := $
(
(
((
(((TARGET_RECOVERY_UI_SCREEN_WIDTH) - 10))
TARGET_RECOVERY_UI_SCREEN_WIDTH ?= 720
2.text_name 是生成的recovery图片的名称,是从 $(PRIVATE_RECOVERY_BACKGROUND_TEXT_LIST)
和$(PRIVATE_RECOVERY_WIPE_DATA_TEXT_LIST)
这两个集合变量中遍历而来的
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_BACKGROUND_TEXT_LIST := \
recovery_installing \
recovery_installing_security \
recovery_erasing \
recovery_error \
recovery_no_command
$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_WIPE_DATA_TEXT_LIST := \
recovery_cancel_wipe_data \
recovery_factory_data_reset \
recovery_try_again \
recovery_wipe_data_menu_header \
recovery_wipe_data_confirmation
3.DEFAULT_FONT_SIZE = 40; 默认字体大小,单位是 px
4.PRIVATE_RECOVERY_FONT_FILES_DIR 字体文件目录
PRIVATE_RECOVERY_FONT_FILES_DIR := $(call intermediates-dir-for,PACKAGING,recovery_font_files)
该目录下的文件是从 PRIVATE_SOURCE_FONTS := $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep) 里面拷过来的
经过搜索发现 recovery_noto-fonts_dep 字体文件在 external/noto-fonts
经过搜索发现 recovery_roboto-fonts_dep 字体文件在 external/roboto-fonts
5.centerAlignment 是否居中
6.PRIVATE_RESOURCE_DIR 字符串资源目录
PRIVATE_RESOURCE_DIR := $(resource_dir)
resource_dir := $(call include-path-for, recovery)/tools/recovery_l10n/res/
7.output_file 输出文件路径
$(eval output_file := $(dir
@
)
/
@)/
@)/(patsubst recovery_%,%_text.png,$(text_name)))
解析字符串代码,第一个参数是字符串资源文件的路径,第二个参数是 locales 语言集合,可以通过参数传递进来,这个方法里面最关键的方法是 getTextString(),这个方式里面是通过DOM解析xml字符串资源文件的
public Map<Locale, String> readLocalizedStringFromXmls(String resourcePath,
Set<String> localesSet) throws IOException, LocalizedStringNotFoundException {
File resourceDir = new File(resourcePath);
if (!resourceDir.isDirectory()) {
throw new LocalizedStringNotFoundException(resourcePath + " is not a directory.");
}
Map<Locale, String> result =
// Overrides the string comparator so that sr is sorted behind sr-Latn. And thus
// recovery can find the most relevant locale when going down the list.
new TreeMap<>(
(Locale l1, Locale l2) -> {
if (l1.toLanguageTag().equals(l2.toLanguageTag())) {
return 0;
}
if (l1.getLanguage().equals(l2.toLanguageTag())) {
return -1;
}
if (l2.getLanguage().equals(l1.toLanguageTag())) {
return 1;
}
return l1.toLanguageTag().compareTo(l2.toLanguageTag());
});
// Find all the localized resource subdirectories in the format of values-$LOCALE
String[] nameList =
resourceDir.list((File file, String name) -> name.startsWith("values-"));
for (String name : nameList) {
String localeString = name.substring(7);
if (localesSet != null && !localesSet.contains(localeString)) {
LOGGER.info("Skip parsing text for locale " + localeString);
continue;
}
File textFile = new File(resourcePath, name + "/strings.xml");
String localizedText;
try {
localizedText = getTextString(textFile, mTextName);
} catch (IOException | ParserConfigurationException | org.xml.sax.SAXException e) {
throw new LocalizedStringNotFoundException(
"Failed to read the translated text for locale " + name, e);
}
Locale locale = getLocaleFromFilename(name);
// Removes the double quotation mark from the text.
result.put(locale, localizedText.substring(1, localizedText.length() - 1));
}
return result;
}
最后的 imageGenerator.generateImage(localizedStringMap, cmd.getOptionValue(“output_file”)); 方法用来生成 recovery 图片资源文件
public void generateImage(Map<Locale, String> localizedTextMap, String outputPath)
throws FontFormatException, IOException {
FontMetrics defaultFontMetrics =
createGraphics(Locale.forLanguageTag("en")).getFontMetrics();
mDefaultFont = defaultFontMetrics.getFont();
mAndroidStringWidth = defaultFontMetrics.stringWidth(ANDROID_STRING);
// The last country variant should be the fallback locale for a given language.
Map<String, Locale> fallbackLocaleMap = new HashMap<>();
int textWidth = 0;
for (Locale locale : localizedTextMap.keySet()) {
// Updates the fallback locale if we have a new language variant. Don't do it for en-XC
// as it's a pseudo-locale.
if (!locale.toLanguageTag().equals("en-XC")) {
fallbackLocaleMap.put(locale.getLanguage(), locale);
}
textWidth = Math.max(textWidth, measureTextWidth(localizedTextMap.get(locale), locale));
}
// Removes the black margins to reduce the size of the image.
resize(textWidth, mImageHeight);
for (Locale locale : localizedTextMap.keySet()) {
// Recovery expects en-US instead of en_US.
String languageTag = locale.toLanguageTag();
Locale fallbackLocale = fallbackLocaleMap.get(locale.getLanguage());
if (locale.equals(fallbackLocale)) {
// Makes the last country variant for a given language be the catch-all for that
// language.
languageTag = locale.getLanguage();
} else if (localizedTextMap.get(locale).equals(localizedTextMap.get(fallbackLocale))) {
LOGGER.info("Skip parsing text for duplicate locale " + locale);
continue;
}
drawText(localizedTextMap.get(locale), locale, languageTag);
}
resize(mImageWidth, mVerticalOffset);
ImageIO.write(mBufferedImage, "png", new File(outputPath));
}
其中 resize()
方法用来去除图片右边的黑色空白,所以一开始输入的图片宽度和最终生成图片宽度是有差异的
ImageIO.write()
就是保存图片到指定路径的方法
总结:由此可知要修改字体的大小只需要修改 DEFAULT_FONT_SIZE
的大小即可
添加修改字符串资源只需要修改 bootable/recovery/tools/recovery_l10n/res/
目录下的字符串文件即可