Android 7.1.1 系統時區,語言,地區,鈴聲配置
阿新 • • 發佈:2018-12-31
Android手機開機後,有一些常用的預設屬性配置,今天就撿主要的說下手機裡預設時區,語言,鈴聲這些常用的屬性配置
當SystemServer啟動後,會在main方法中呼叫SystemServer[email protected]()->[email protected](),在startOtherServices中呼叫mSystemServiceManager.startService(AlarmManagerService.class)啟動AlarmManagerService
除了這個地方,在ServiceStateTracker中fixTimeZone也會用到這個屬性,在執行fixTimeZone時先會呼叫shouldFixTimeZoneNow根據運營商mcc和needToFixTimeZone判斷是否需要修正時區
當滿足條件後就會在fixTimeZone中根據isoCountryCode和配置的屬性"persist.sys.timezone"修復時區,在系統資源time_zones_by_country.xml中counrtycode對應著time_zones如下
(1) persist.sys.locale
(2) persist.sys.language/country/localevar (language不為才空檢查country 和 localevar)
(3) ro.product.locale
(4) ro.product.locale.language/region
ro.config.ringtone
ro.config.notification_sound
ro.config.alarm_alert
在系統啟動MediaScanner初始化時,會利用這三個屬性,設定預設的鈴聲
1、配置預設時區
對於China來說預設時區是GMT+08:00,如果系統中沒有配置預設時區的屬性,時區肯定不是中國標準時間,控制時區的屬性為persist.sys.timezone,只需要在配置系統預設屬性的地方加上下面屬性就行
關於屬性的配置可以參考《Android 7.1.1中SystemProperties詳解》,知道了怎麼配置後好奇為啥要這樣配置,就看來看android系統中對這個屬性的使用#在mk檔案中配置系統屬性如下 PRODUCT_PROPERTY_OVERRIDES += persist.sys.timezone=Asia/Shanghai #或者 ADDITIONAL_BUILD_PROPERTIES += persist.sys.timezone=Asia/Shanghai #在*.prop檔案配置如下 persist.sys.timezone=Asia/Shanghai
當SystemServer啟動後,會在main方法中呼叫SystemServer[email protected]()->[email protected](),在startOtherServices中呼叫mSystemServiceManager.startService(AlarmManagerService.class)啟動AlarmManagerService
當AlarmManagerService啟動後,都會根據TIMEZONE_PROPERTY呼叫setTimeZoneImpl設定時區,置於這個方法具體怎麼實現的就不在囉嗦了,有興趣可以自己去看看。//frameworks/base/services/core/java/com/android/server/AlarmManagerService.java static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; public void onStart() { ... // We have to set current TimeZone info to kernel // because kernel doesn't keep this after reboot setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); }
除了這個地方,在ServiceStateTracker中fixTimeZone也會用到這個屬性,在執行fixTimeZone時先會呼叫shouldFixTimeZoneNow根據運營商mcc和needToFixTimeZone判斷是否需要修正時區
其中needToFixTimeZone是在收到運營商上報RIL_UNSOL_NITZ_TIME_RECEIVED事件後,才會把needToFixTimeZone置為true,關於NITZ可以檢視《Android 7.1.1時間更新NITZ和NTP詳解》//frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java protected boolean shouldFixTimeZoneNow(Phone phone, String operatorNumeric, String prevOperatorNumeric, boolean needToFixTimeZone) { // Return false if the mcc isn't valid as we don't know where we are. // Return true if we have an IccCard and the mcc changed or we // need to fix it because when the NITZ time came in we didn't // know the country code. // If mcc is invalid then we'll return false int mcc; try { mcc = Integer.parseInt(operatorNumeric.substring(0, 3)); } catch (Exception e) { if (DBG) { log("shouldFixTimeZoneNow: no mcc, operatorNumeric=" + operatorNumeric + " retVal=false"); } return false; } // If prevMcc is invalid will make it different from mcc // so we'll return true if the card exists. int prevMcc; try { prevMcc = Integer.parseInt(prevOperatorNumeric.substring(0, 3)); } catch (Exception e) { prevMcc = mcc + 1; } // Determine if the Icc card exists boolean iccCardExist = false; if (mUiccApplcation != null) { iccCardExist = mUiccApplcation.getState() != AppState.APPSTATE_UNKNOWN; } // Determine retVal boolean retVal = ((iccCardExist && (mcc != prevMcc)) || needToFixTimeZone); if (DBG) { long ctm = System.currentTimeMillis(); log("shouldFixTimeZoneNow: retVal=" + retVal + " iccCardExist=" + iccCardExist + " operatorNumeric=" + operatorNumeric + " mcc=" + mcc + " prevOperatorNumeric=" + prevOperatorNumeric + " prevMcc=" + prevMcc + " needToFixTimeZone=" + needToFixTimeZone + " ltod=" + TimeUtils.logTimeOfDay(ctm)); } return retVal; }
當滿足條件後就會在fixTimeZone中根據isoCountryCode和配置的屬性"persist.sys.timezone"修復時區,在系統資源time_zones_by_country.xml中counrtycode對應著time_zones如下
//frameworks/base/core/res/res/xml/time_zones_by_country.xml
<!-- CHINA, 8:00 -->
<timezone code="cn">Asia/Shanghai</timezone>
<timezone code="cn">Asia/Harbin</timezone>
<timezone code="cn">Asia/Chongqing</timezone>
<timezone code="cn">Asia/Urumqi</timezone>
<timezone code="cn">Asia/Kashgar</timezone>
2、配置預設地區和語言配置
當Dalvik虛擬機器啟動後呼叫[email protected]()檢查下列系統屬性,並返回列表中的第一個非空屬性。(1) persist.sys.locale
(2) persist.sys.language/country/localevar (language不為才空檢查country 和 localevar)
(3) ro.product.locale
(4) ro.product.locale.language/region
//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 productLocale = getProperty("ro.product.locale", "");
if (!productLocale.empty()) {
return productLocale;
}
// If persist.sys.locale and ro.product.locale are missing,
// construct a locale value from the individual locale components.
const std::string productLanguage = getProperty("ro.product.locale.language", "en");
const std::string productRegion = getProperty("ro.product.locale.region", "US");
//都沒有配置的話,預設返回en-US
return productLanguage + "-" + productRegion;
}
在系統資原始檔locale_config.xml,有"語言-地區"的所有列表,下面只保留了國內的
//frameworks/base/core/res/res/values/locale_config.xml
<resources>
<string-array translatable="false" name="supported_locales">
...
<item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) -->
<item>zh-Hans-CN</item> <!-- Chinese (Simplified Han,China) -->
<item>zh-Hans-HK</item> <!-- Chinese (Simplified Han,Hong Kong) -->
<item>zh-Hans-MO</item> <!-- Chinese (Simplified Han,Macau) -->
<item>zh-Hans-SG</item> <!-- Chinese (Simplified Han,Singapore) -->
<item>zh-Hant-HK</item> <!-- Chinese (Traditional Han,Hong Kong) -->
<item>zh-Hant-MO</item> <!-- Chinese (Traditional Han,Macau) -->
<item>zh-Hant-TW</item> <!-- Chinese (Traditional Han,Taiwan) -->
<item>zu-ZA</item> <!-- Zulu (South Africa) -->
</string-array>
</resources>
3、預設鈴聲配置
系統中預設鈴聲分為三類,來電預設鈴聲,通知預設鈴聲,鬧鈴預設鈴聲,分別對應一下屬下ro.config.ringtone
ro.config.notification_sound
ro.config.alarm_alert
在系統啟動MediaScanner初始化時,會利用這三個屬性,設定預設的鈴聲
//frameworks/base/media/java/android/media/MediaScanner.java
//Settings.System.RINGTONE = "ringtone";
//Settings.System.NOTIFICATION_SOUND = "notification_sound";
//Settings.System.ALARM_ALERT = "alarm_alert";
private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
private void setDefaultRingtoneFileNames() {
mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.RINGTONE);
mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.NOTIFICATION_SOUND);
mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.ALARM_ALERT);
}
利用doScanFile所有掃描所有檔案,呼叫endFile(),把所有media資訊插入資料庫,在插入資料庫時候會根據mDefaultRingtoneFilename,來判斷檔案是否存在,來決定是否設定對應預設鈴聲
//frameworks/base/media/java/android/media/MediaScanner.java
private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications,
boolean alarms, boolean music, boolean podcasts)
throws RemoteException {
// update database
...
if (notifications && !mDefaultNotificationSet) {
if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
needToSetSettings = true;
}
} else if (ringtones && !mDefaultRingtoneSet) {
if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
needToSetSettings = true;
}
} else if (alarms && !mDefaultAlarmSet) {
if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
needToSetSettings = true;
}
}
...
if(needToSetSettings) {
if (notifications) {
setRingtoneIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
mDefaultNotificationSet = true;
} else if (ringtones) {
setRingtoneIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
} else if (alarms) {
setRingtoneIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
mDefaultAlarmSet = true;
}
}
return result;
}
最後呼叫setRingtoneIfNotSet設定鈴聲,到這預設鈴聲就設定完成了
private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) {
if (wasRingtoneAlreadySet(settingName)) {//判斷是否已經設定
return;
}
ContentResolver cr = mContext.getContentResolver();
String existingSettingValue = Settings.System.getString(cr, settingName);
if (TextUtils.isEmpty(existingSettingValue)) {
final Uri settingUri = Settings.System.getUriFor(settingName);
final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId);
//設定預設來電,通知,鬧鈴鈴聲
RingtoneManager.setActualDefaultRingtoneUri(mContext,
RingtoneManager.getDefaultType(settingUri), ringtoneUri);
}
Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}