看过就忘!为了照顾自己的痴呆脑,劳累双手记录一下。
packages/apps/Settings/AndroidManifest.xml
<activity android:name="Settings$InputMethodAndLanguageSettingsActivity"
android:label="@string/language_keyboard_settings_title"
android:icon="@drawable/ic_settings_language"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.inputmethod.InputMethodAndLanguageSettings" />
</activity>
[UI 主view]
packages/apps/Settings/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
public void onCreate(Bundle icicle) {
addPreferencesFromResource(R.xml.language_settings);
}
packages/apps/Settings/res/xml/language_settings.xml/language_settings
<PreferenceScreen
android:key="phone_language"
android:title="@string/phone_language"
android:fragment="com.android.settings.localepicker.LocaleListEditor"
/>
packages/apps/Settings/src/com/android/settings/localepicker/LocaleListEditor.java
@Override
public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
mAdapter.addLocale(locale);
updateVisibilityOfRemoveMenu();
}
packages/apps/Settings/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
void addLocale(LocaleStore.LocaleInfo li) {
mFeedItemList.add(li);
notifyItemInserted(mFeedItemList.size() - 1);
doTheUpdate();
}
public void updateLocalesWhenAnimationStops(final LocaleList localeList) {
final RecyclerView.ItemAnimator itemAnimator = mParentView.getItemAnimator();
itemAnimator.isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
@Override
public void onAnimationsFinished() {
LocalePicker.updateLocales(mLocalesToSetNext);
}
});
}
frameworks/base/core/java/com/android/internalapp/LocalePicker.java
public static void updateLocales(LocaleList locales) {
try {
final IActivityManager am = ActivityManagerNative.getDefault();
final Configuration config = am.getConfiguration();
config.setLocales(locales);
config.userSetLocale = true;
am.updatePersistentConfiguration(config);
// Trigger the dirty bit for the Settings Provider.
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
// Intentionally left blank
}
}
frameworks/base/core/java/android/app/ActivityManagerNative .java
static public IActivityManager getDefault() {
return gDefault.get();
}
ActivityManagerNative 的 getDefault() ,返回的是远程服务对象 ActivityManagerServices.java 在本地的一个代理, 最终调用的是ActivityManagerServices.java 中的 updateCofiguration() 函数。
frameworks/base/core/java/android/app/IActivityManager.java
public void updatePersistentConfiguration(Configuration values) throws RemoteException;
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
boolean initLocale, boolean persistent, int userId, boolean deferResume) {
if (values != null) {
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
if (changes != 0) {
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
final LocaleList locales = values.getLocales();
int bestLocaleIndex = 0;
if (locales.size() > 1) {
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales =
Resources.getSystem().getAssets().getLocales();
}
bestLocaleIndex = Math.max(0,
locales.getFirstMatchIndex(mSupportedSystemLocales));
}
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
locales.get(bestLocaleIndex)));
}
}
return kept;
}
frameworks/base/core/java/android/content/res/Configuration.java
public @Config int updateFrom(@NonNull Configuration delta) {
int changed = 0;
fixUpLocaleList();
delta.fixUpLocaleList();
if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
changed |= ActivityInfo.CONFIG_LOCALE;
mLocaleList = delta.mLocaleList;
// delta.locale can't be null, since delta.mLocaleList is not empty.
if (!delta.locale.equals(locale)) {
locale = (Locale) delta.locale.clone();
// If locale has changed, then layout direction is also changed ...
changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
// ... and we need to update the layout direction (represented by the first
// 2 most significant bits in screenLayout).
setLayoutDirection(locale);
}
}
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
changed |= ActivityInfo.CONFIG_LOCALE;
userSetLocale = true;
}
return changed;
}
target locale file : "persist.sys.locale" (data/property/persist.sys.locale)
2) 所有语言 文件
packages/apps/Settings/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
import android.os.LocaleList (全部 语言)
import com.android.internal.app.LocaleHelper
import com.android.internal.app.LocalePicker (已选 语言)
import java.util.Locale
private static String getLocaleNames(Context context) {
final LocaleList locales = LocalePicker.getLocales();
final Locale displayLocale = Locale.getDefault();
return LocaleHelper.toSentenceCase(
LocaleHelper.getDisplayLocaleList(
locales, displayLocale, 2 /* Show up to two locales from the list */),
displayLocale);
}
libcore/ojluni/src/main/java/java/util/Locale.java
external/libgdx/backends/gdx/-backends-gwt/src/com/badlogic/gdx/backends/gwt/emu/jaba/util/Locale.java
frameworks/base/core/java/com/android/internalapp/LocalePicker.java
packages/apps/Settings/src/com/android/settings/localepicker/LocaleListEditor.java
private void configureDragAndDrop(View view) {
mAddLanguage = view.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
getContext(), LocaleListEditor.this, false /* translate only */);
}
});
}
frameworks/base/core/java/com/android/internalapp/LocalePickerWithRegion.java
public static LocalePickerWithRegion createLanguagePicker(Context context,
LocaleSelectedListener listener, boolean translatedOnly) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
return localePicker;
}
private boolean setListener(Context context, LocaleSelectedListener listener,
LocaleStore.LocaleInfo parent, boolean translatedOnly) {
final HashSet<String> langTagsToIgnore = new HashSet<>();
if (!translatedOnly) {
final LocaleList userLocales = LocalePicker.getLocales();
final String[] langTags = userLocales.toLanguageTags().split(",");
Collections.addAll(langTagsToIgnore, langTags);
}
if (parent != null) {
} else {
mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
null /* no parent */, translatedOnly);
}
return true;
}
frameworks/base/core/java/com/android/internalapp/LocaleStore.java
public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables,
LocaleInfo parent, boolean translatedOnly) {
fillCache(context);
for (LocaleStore.LocaleInfo li : sLocaleCache.values()) {
}
return result;
}
public static void fillCache(Context context) {
for (String localeId : LocalePicker.getSupportedLocales(context)) {
LocaleInfo li = new LocaleInfo(localeId);
sLocaleCache.put(li.getId(), li);
}
}
frameworks/base/core/java/com/android/internalapp/LocalePicker.java
public static String[] getSupportedLocales(Context context) {
return context.getResources().getStringArray(R.array.supported_locales);
}
全部语言 file : frameworks/base/core/res/res/values/locale_config.xml
3) LocalePicker.getLocales()
frameworks/base/core/java/com/android/internalapp/LocalePicker.java
public static LocaleList getLocales() {
try {
return ActivityManagerNative.getDefault()
.getConfiguration().getLocales();
} catch (RemoteException e) {
// If something went wrong
return LocaleList.getDefault();
}
}
frameworks/base/core/java/android/content/res/Configuration.java
public @NonNull LocaleList getLocales() {
fixUpLocaleList();
return mLocaleList;
}
private void fixUpLocaleList() {
if ((locale == null && !mLocaleList.isEmpty()) ||
(locale != null && !locale.equals(mLocaleList.get(0)))) {
mLocaleList = locale == null ? LocaleList.getEmptyLocaleList() : new LocaleList(locale);
}
}
frameworks/base/core/java/android/os/LocaleList.java
private static final LocaleList sEmptyLocaleList = new LocaleList();
public LocaleList(@NonNull Locale... list) {
if (list.length == 0) {
mList = sEmptyList;
mStringRepresentation = "";
} else {
final Locale[] localeList = new Locale[list.length];
final HashSet<Locale> seenLocales = new HashSet<Locale>();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.length; i++) {
final Locale l = list[i];
if (l == null) {
throw new NullPointerException("list[" + i + "] is null");
} else if (seenLocales.contains(l)) {
throw new IllegalArgumentException("list[" + i + "] is a repetition");
} else {
final Locale localeClone = (Locale) l.clone();
localeList[i] = localeClone;
sb.append(localeClone.toLanguageTag());
if (i < list.length - 1) {
sb.append(',');
}
seenLocales.add(localeClone);
}
}
mList = localeList;
mStringRepresentation = sb.toString();
}
}