1.前言
在12.0的系统ROM产品定制化开发中,在系统中的语言和输入法菜单中,在添加语言的默认列表中对于同一类型的语言就可以会出现一中语言,比如多种英语类型 就显示的不全,所以要求显示所有的英语类型,这样就需要了解语言列表的加载流程然后加载所有的英语类型,接下来具体分析功能实现
2.系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心类
frameworks/base/core/java/com/android/internal/app/LocalePickerWithRegion.java
/frameworks/opt/localepicker/src/com/android/localepicker/LocaleStore.java
packages\apps\Settings\src\com\android\settings\localepicker\LocalePickerWithRegionActivity.java
3.系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能分析和实现
在系统Settings中,在语言和输入法菜单中,在add a lanuage添加语言的菜单中,点击这个button后就进入到了
系统语言列表的页面,而在这个页面就是LocalePickerWithRegionActivity.java,这个类就负责加载当前系统的语言列表,然后点击语言选项后,就添加到默认语言列表项,通过移动到首项就成为当前系统的默认语言
切换语言Settings 处理跳转到 framework 的入口是LocalePicker的updateLocales方法,
通过 Binder 获取 ActivityManager 的一个服务代理对象,来处理 实现方法是 updatePersistentConfigurationWithAttribution
3.1 LocalePickerWithRegionActivity.java的相关语言分析
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在LocalePickerWithRegionActivity.java的类中,主要就是为了实现系统语言列表项的加载,然后实现通过点击语言项
来添加语言到默认语言列表,接下来看下是如何添加语言列表的
public class LocalePickerWithRegionActivity extends Activity
implements LocalePickerWithRegion.LocaleSelectedListener {
private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
this, LocalePickerWithRegionActivity.this, false /* translate only */);
getFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(android.R.id.content, selector)
.addToBackStack(PARENT_FRAGMENT_NAME)
.commit();
}
.....
}
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在LocalePickerWithRegionActivity.java的类中, LocalePickerWithRegion.createLanguagePicker方法就是获取当前
系统语言的列表项,然后通过replace(android.R.id.content, selector)加载到当前列表中,所以主要还是通过LocalePickerWithRegion类来加载语言列表项,接下来分析下LocalePickerWithRegion的相关方法
3.2 LocalePickerWithRegion的相关方法分析
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在通过上述的Settings中的分析得知,在framework层中,主要是通过LocalePickerWithRegion.createLanguagePicker
来调用相关的方法来加载系统语言列表,接下来分析下相关功能实现
public static LocalePickerWithRegion createLanguagePicker(Context context,
LocaleSelectedListener listener, boolean translatedOnly, String appPackageName,
OnActionExpandListener onActionExpandListener) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
localePicker.setOnActionExpandListener(onActionExpandListener);
localePicker.setListener(
context, listener, /* parent */ null, translatedOnly, appPackageName);
return localePicker;
}
private boolean setListener(Context context, LocaleSelectedListener listener,
LocaleStore.LocaleInfo parent, boolean translatedOnly, String appPackageName) {
this.mParentLocale = parent;
this.mListener = listener;
this.mTranslatedOnly = translatedOnly;
this.mAppPackageName = appPackageName;
setRetainInstance(true);
final HashSet<String> langTagsToIgnore = new HashSet<>();
LocaleStore.LocaleInfo appCurrentLocale =
LocaleStore.getAppCurrentLocaleInfo(context, appPackageName);
boolean isForCountryMode = parent != null;
if (!TextUtils.isEmpty(appPackageName) && !isForCountryMode) {
// Filter current system locale to add them into suggestion
LocaleList systemLangList = LocaleList.getDefault();
for(int i = 0; i < systemLangList.size(); i++) {
langTagsToIgnore.add(systemLangList.get(i).toLanguageTag());
}
if (appCurrentLocale != null) {
Log.d(TAG, "appCurrentLocale: " + appCurrentLocale.getLocale().toLanguageTag());
langTagsToIgnore.add(appCurrentLocale.getLocale().toLanguageTag());
} else {
Log.d(TAG, "appCurrentLocale is null");
}
} else if (!translatedOnly) {
final LocaleList userLocales = LocalePicker.getLocales();
final String[] langTags = userLocales.toLanguageTags().split(",");
Collections.addAll(langTagsToIgnore, langTags);
}
if (isForCountryMode) {
mLocaleList = LocaleStore.getLevelLocales(context,
langTagsToIgnore, parent, translatedOnly);
if (mLocaleList.size() <= 1) {
if (listener != null && (mLocaleList.size() == 1)) {
listener.onLocaleSelected(mLocaleList.iterator().next());
}
return false;
}
} else {
mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
null /* no parent */, translatedOnly);
}
Log.d(TAG, "mLocaleList size: " + mLocaleList.size());
....
}
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在通过上述的LocalePickerWithRegion.java中的相关源码分析得知,在重要是这一步,调用了localePicker.setListener,localePicker是LocalePickerWithRegion
然后实例化的对象,于是将流程传递给了本类的setListener方法,所以说具体添加流程是在setListener方法中实现,而在
setListener方法中,LocaleStore.getAppCurrentLocaleInfo这部分的逻辑是 获取已经添加的语言列表,作为需要忽略的部分,毕竟已经添加的,还能再添加就不合理了
而在以下的代码中,通过if (parent != null)【判断】这里做了选择的语言不为空的判断后,就将逻辑流程 传递给了 LocaleStore.java
的getLevelLocales方法,从而获得一个新的已添加语言列表,所以最终核心的代码就是调用LocaleStore.getLevelLocales
来最终实现添加系统语言列表功能,接下来分析下LocaleStore.getLevelLocales的相关代码
3.3 LocaleStore.java的相关代码实现
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在LocalePickerWithRegion.java中的相关源码分析,最中的实现语言加载部分是在LocaleStore.getLevelLocales的相关代码
接下来具体看下相关源码实现
public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables,
LocaleInfo parent, boolean translatedOnly) {
fillCache(context);
String parentId = parent == null ? null : parent.getId();
HashSet<LocaleInfo> result = new HashSet<>();
for (LocaleStore.LocaleInfo li : sLocaleCache.values()) {
int level = getLevel(ignorables, li, translatedOnly);
if (level == 2) {
if (parent != null) { // region selection
if (parentId.equals(li.getParent().toLanguageTag())) {
result.add(li);
}
} else { // language selection
if (li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
result.add(li);
} else {
- result.add(getLocaleInfo(li.getParent()));
+ if(!android.text.TextUtils.isEmpty(li.getId())&&li.getId().contains("en-")){
+ result.add(li);
+ }else{
+ result.add(getLocaleInfo(li.getParent()));
+ }
}
}
}
}
return result;
}
在实现系统设置语言和输入法菜单Launage语言列表增加支持多种英语语言功能的核心功能中,在通过上述的分析得知,
在LocaleStore.java中的相关源码分析,在getLevelLocales(Context context, Set<String> ignorables,
LocaleInfo parent, boolean translatedOnly)中,会通过遍历 sLocaleCache.values()这个系统语言的列表中
然后添加到result这个集合中作为返回值,而在其中的 核心代码中, result.add(getLocaleInfo(li.getParent()));这段
代码就是为啥在系统中有好几种英语语言的类型 其实在语言列表中,只见到一种的原因,这里就是添加一中到系统语言
显示列表的,所以就会添加判断if(!android.text.TextUtils.isEmpty(li.getId())&&li.getId().contains("en-"))
这样就表示当前是英语类型 就直接添加到语言列表中了,其他的就会过滤掉相同的语言类型,这样就实现了功能