Android手机开机后,有一些常用的默认属性配置,今天就捡主要的说下手机里默认时区,语言,铃声这些常用的属性配置
1、配置默认时区
对于China来说默认时区是GMT+08:00,如果系统中没有配置默认时区的属性,时区肯定不是中国标准时间,控制时区的属性为persist.sys.timezone,只需要在配置系统默认属性的地方加上下面属性就行
#在mk文件中配置系统属性如下
PRODUCT_PROPERTY_OVERRIDES += persist.sys.timezone=Asia/Shanghai
#或者
ADDITIONAL_BUILD_PROPERTIES += persist.sys.timezone=Asia/Shanghai
#在*.prop文件配置如下
persist.sys.timezone=Asia/Shanghai
关于属性的配置可以参考《
Android 7.1.1中SystemProperties详解》,知道了怎么配置后好奇为啥要这样配置,就看来看android系统中对这个属性的使用
当SystemServer启动后,会在main方法中调用SystemServer@run()->SystemServer@startOtherServices(),在startOtherServices中调用mSystemServiceManager.startService(AlarmManagerService.class)启动AlarmManagerService
//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));
}
当AlarmManagerService启动后,都会根据TIMEZONE_PROPERTY调用setTimeZoneImpl设置时区,置于这个方法具体怎么实现的就不在啰嗦了,有兴趣可以自己去看看。
除了这个地方,在ServiceStateTracker中fixTimeZone也会用到这个属性,在执行fixTimeZone时先会调用shouldFixTimeZoneNow根据运营商mcc和needToFixTimeZone判断是否需要修正时区
//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;
}
其中needToFixTimeZone是在收到运营商上报RIL_UNSOL_NITZ_TIME_RECEIVED事件后,才会把needToFixTimeZone置为true,关于NITZ可以查看《
Android 7.1.1时间更新NITZ和NTP详解》
当满足条件后就会在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虚拟机启动后调用AndroidRuntime.cpp@readLocale()检查下列系统属性,并返回列表中的第一个非空属性。
(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);
}