Android N 首次开机不随SIM卡自适应语言
Android N和Android M上一样默认设计首次开机不会随Sim卡自适应语言,如要修改为随Sim卡自适应,可参考如下修改(Android N上language与M上有较大变化,可以同时选择多种语言,所以修改方案与M上也有所不同)。
如果修改之后发现首次开机仍然无法自适应语言且版本是有安装GMS包, 请将下面的canUpdateLocale()函数中的“return !(userHasPersistedLocale() || isDeviceProvisioned(context));” 修改为"return !(userHasPersistedLocale() && isDeviceProvisioned(context));"
Android N修改方案
- /frameworks/opt/telephony/src/java/com/android/internal/telephony/MccTable.java
/**
* Updates MCC and MNC device configuration information for application retrieving
* correct version of resources. If MCC is 0, MCC and MNC will be ignored (not set).
* @param context Context to act on.
* @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end
* @param fromServiceState true if coming from the radio service state, false if from SIM
*/
public static void updateMccMncConfiguration(Context context, String mccmnc,
boolean fromServiceState) {
Slog.d(LOG_TAG, "updateMccMncConfiguration mccmnc='" + mccmnc + "' fromServiceState=" + fromServiceState);
...
try {
mcc = Integer.parseInt(mccmnc.substring(0,3));
mnc = Integer.parseInt(mccmnc.substring(3));
} catch (NumberFormatException e) {
Slog.e(LOG_TAG, "Error parsing IMSI: " + mccmnc);
return;
}
Slog.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
Locale mccLocale = null; //添加这行
if (mcc != 0) {
setTimezoneFromMccIfNeeded(context, mcc);
mccLocale = getLocaleFromMcc(context, mcc); //添加这行
}
if (fromServiceState) {
setWifiCountryCodeFromMcc(context, mcc);
} else {
// from SIM
try {
Configuration config = new Configuration();
boolean updateConfig = false;
if (mcc != 0) {
config.mcc = mcc;
config.mnc = mnc == 0 ? Configuration.MNC_ZERO : mnc;
updateConfig = true;
}
if (mccLocale != null) { //添加这行
Configuration conLocale = new Configuration(); //添加这行
conLocale = ActivityManagerNative.getDefault().getConfiguration(); //添加这行
LocaleList userLocale = conLocale.getLocales(); //添加这行
LocaleList newUserLocale = new LocaleList(mccLocale,userLocale); //添加这行
config.setLocales(newUserLocale); //添加这行
updateConfig = true; //添加这行
} //添加这行
if (updateConfig) {
Slog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
ActivityManagerNative.getDefault().updateConfiguration(config);
} else {
Slog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Can't update configuration", e);
}
}
} else {
if (fromServiceState) {
// an empty mccmnc means no signal - tell wifi we don't know
setWifiCountryCodeFromMcc(context, 0);
}
}
}
//添加函数 begin
private static boolean canUpdateLocale(Context context) {
return !(userHasPersistedLocale() || isDeviceProvisioned(context));
}
private static boolean userHasPersistedLocale() {
String persistSysLanguage = SystemProperties.get("persist.sys.locale", "");
String persistSysCountry = SystemProperties.get("persist.sys.country", "");
return !(persistSysLanguage.isEmpty() && persistSysCountry.isEmpty());
}
private static boolean isDeviceProvisioned(Context context) {
try {
return Settings.Global.getInt(
context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED) != 0;
} catch (Settings.SettingNotFoundException e) {
return false;
}
}
// 添加函数 end
private static Locale getLocaleForLanguageCountry(Context context, String language,
String country) {
if (language == null) {
Slog.d(LOG_TAG, "getLocaleForLanguageCountry: skipping no language");
return null; // no match possible
}
if (country == null) {
country = ""; // The Locale constructor throws if passed null.
}
if(!canUpdateLocale()){ //添加这行
return null; //添加这行
} //添加这行
final Locale target = new Locale(language, country);
...
return null;
}
- 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) {
int changes = 0;
...
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) { // 删除这行
if (!initLocale && !values.getLocales().isEmpty()) { //添加这行
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));
}
if(values.userSetLocale){ //添加这行
SystemProperties.set("persist.sys.locale", //添加这行
locales.get(bestLocaleIndex).toLanguageTag()); //添加这行
}else{ //添加这行
SystemProperties.set("persist.sys.simLocale", //添加这行
locales.get(bestLocaleIndex).toLanguageTag()); //添加这行
} //添加这行
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)));
}
...
- /frameworks/base/core/jni/AndroidRuntime.cpp
const std::string readLocale()
{
const std::string locale = getProperty("persist.sys.locale", "");
if (!locale.empty()) {
return locale;
}
const std::string language = getProperty("persist.sys.language", "");
if (!language.empty()) {
const std::string country = getProperty("persist.sys.country", "");
const std::string variant = getProperty("persist.sys.localevar", "");
std::string out = language;
if (!country.empty()) {
out = out + "-" + country;
}
if (!variant.empty()) {
out = out + "-" + variant;
}
return out;
}
const std::string simLocale = getProperty("persist.sys.simLocale", ""); //添加这行
if (!simLocale.empty()) { //添加这行
return simLocale; //添加这行
} //添加这行
const std::string productLocale = getProperty("ro.product.locale", "");
if (!productLocale.empty()) {
return productLocale;
}
...
}
Android O,P首次开机不随SIM卡自适应语言
Android O、P上的修改与Android N上一样,只是方法名不同
Android O修改方案
- /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
...
// 要修改的代码完全一致
}
Android P修改方案
/** Update default (global) configuration and notify listeners about changes. */
private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
mTempConfig.setTo(getGlobalConfiguration());
final int changes = mTempConfig.updateFrom(values);
// 要修改的代码完全一致
...
}