一般在新項目開始之初,我們需要針對客戶需求進行各種系統默認屬性的配置,通常這些屬性都是通過build.prop、settings.db、default.xml、一些功能package下的config.xml等來進行初始化配置的。
那麼,要滿足客戶的定制需求,對於我們開發者來說,修改SettingsProvider默認值,而第一次開機時,用來填充settings.db的數據都是從frameworks/base/packages/SettingsProvider/res/values/defaults.xml這個文件來讀取的。所以大部分的系統屬性都是通過修改此處的xml節點來修改的。當然有一些屬性是在device下的project.mk中去修改使其編譯時添加到build.prop中去。
接下來,我將從我所參與過的項目中,去一點點的記錄需要修改的屬性都怎麼設置。
對於Android手機ODM界的朋友,通讀這篇文章後,基本上能完成項目前期70%的適配工作(如果是做MTK平台的話,那更好,可以用來控制的宏變量更加豐富)。
1.去掉“亮度”中的自動調節
第一步、修改frameworks/base/core/res/res/values/config.xml中的
false
第二步、在Marvell1908平台中,沒有根據此property來確定“自動”按鈕的顯示還是隱藏,所以還需在SystemUI中動態確定該CheckBox的顯示與否:
BrightnessController.java中添加如下方法
privatevoidupdateAutomaticButton(booleanautomatic){
android.util.Log.d(TAG,"Automaticbuttonaviliable:"+automatic);
if(null!=mControl){
mControl.setAutomaticAvailable(automatic);
}
}
在updateMode()中調用該方法:
privatevoidupdateMode(){
//……
}else{
mControl.setChecked(false);
updateIcon(false);
}
updateAutomaticButton(mAutomaticAvailable);
}
在ToggleSlider.java中添加接口:
publicvoidsetAutomaticAvailable(booleanautoBrightness){
if(null!=mToggle){
//mToggle.setWidth(autoBrightness?48:0);
mToggle.getLayoutParams().width=autoBrightness?48:0;
mToggle.setOnCheckedChangeListener(autoBrightness?this:null);
}
}
Tip:
不支持光感設備去掉“自動調節亮度”需要考慮桌面小部件、下拉狀態欄、亮度調節Dialog以及第三方apk這四個方面的Icon的顯示問題。如果修改booleanproperty還不能達到效果,就需要考慮第二步。
2.修改“亮度”的最值、默認值、半暗值
修改frameworks/base/core/res/res/values/config.xml中的
10
255
102
10
3.修改開機時的默認亮度
修改frameworks/base/packages/SettingsProvider/res/values/defaults.xml中的
51
4.修改開關機鈴聲
開關機動畫相關所在路徑是在frameworks/base/cmds/bootanimation/中去操作的(不同平台略有不同);
Android設備的鈴聲資源都是在frameworks/base/data/sounds中
Marvell平台是在frameworks/base/cmds/bootanimation/BootAudio.cpp
#defineUSER_BOOTMUSIC_FILE"/data/local/bootupmusic.mp3"
#defineSYSTEM_BOOTMUSIC_FILE"/system/media/bootupmusic.mp3"
#defineUSER_SHUTDOWNMUSIC_FILE"/data/local/shutdownmusic.mp3"
#defineSYSTEM_SHUTDOWNMUSIC_FILE"/system/media/shutdownmusic.mp3"
用需要替換的開關機鈴聲overlay對應的文件/system/media/bootupmusic.mp3和/system/media/shutdownmusic.mp3即可,注意資源名稱要一致,改為對應的bootupmusic.mp3或者shutdownmusic.mp3
Qualcomm平台是在frameworks/base/cmds/bootanimation/bootanimation_main.cpp中
voidBootAnimation::playBackgroundMusic(void)
{
charbootAudioFile[]="/system/media/boot.wav";
charshutdownAudioFile[]="/system/media/shutdown.wav";
//……
}
需要將替換的資源overlay下boot.wavshutdown.wav注意名稱一致,格式也必須一致。或者直接修改這裡的cpp代碼。
5.修改Android默認壁紙
Overlay掉frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.jpg即可
6.編譯版本時不生成odex
一般odex化是在4.0以後的版本中有的功能,odex化可以使系統的啟動和程序運行速度大大提高,穩定性不變。但是編譯時生成odex包會大大增加system.img的體積,不利於ota升級,t卡升級,所以在編譯時可以去odex。
需要在.mk文件中添加屬性:
#removeodex
DISABLE_DEXPREOPT:=true
7.修改默認來電鈴聲、通知鈴聲
首先需要檢查要修改的資源是否在frameworks/base/data/sounds/下的notifications/和ringtones/中,如果沒有,需要添加上去,將資源在該目錄下的.mk中按照其他的資源的方式添加進去。然後在device下的.mk中添加屬性:
ADDITIONAL_BUILD_PROPERTIES+=/
ro.config.ringtone=Andromeda.ogg/
ro.config.notification_sound=Heaven.ogg
注意,在不同的平台中properties的宏定義可能有所不同,在Marvell中ADDITIONAL_BUILD_PROPERTIES為property的overlayproperty而在Qualcomm中buildpeoperty的宏為PRODUCT_PROPERTY_OVERRIDES;要預置的鈴聲資源需要在設備中存在,不然默認鈴聲就為“無”,這個可以去frameworks/base/data/sounds/下面查看,然後對應修改AllAudio.mkl文件即可。
8.修改語言列表、默認語言
在.mk中修改屬性:
#onlyusezh_CN,usanddefaultCN
PRODUCT_LOCALES+=zh_CNen_US
PRODUCT_PROPERTY_OVERRIDES+=/
persist.sys.language=zh/
persist.sys.country=CN/
ro.product.locale.language=zh/
ro.product.locale.region=CN
注意是+=而不是:=
:=覆蓋前面的值
+=添加=後面的值
?=如果沒有被賦值,就賦值於=後面的值
在這裡就是將這些屬性全部覆蓋之前的定義。可以看到在這裡定義了默認語言為中文,默認地區為中國。並且只有中文英文兩種。
9.修改默認時區
在.mk中添加:
PRODUCT_PROPERTY_OVERRIDES+=/
persist.sys.timezone=Asia/Shanghai
另外還有一種方法:
在init.rc中添加
#setdefaulttimezone
setproppersist.sys.timezoneAsia/Shanghai
直接在底層修改默認時區(如果不熟悉,最好讓驅動工程師來修改)
10.修改開關機動畫
與修改開關機鈴聲一樣,開關機動畫相關代碼都是在frameworks/base/cmds/bootanimation/中,需要我們根據代碼去制作動畫。
一般在Android設備中,開關機動畫都是通過幀動畫來實現的。
以Marvell平台為參考:
frameworks/base/cmds/bootanimation/BootAnimation.cpp
#defineUSER_BOOTANIMATION_FILE"/data/local/bootanimation.zip"
#defineSYSTEM_BOOTANIMATION_FILE"/system/media/bootanimation.zip"
//addshutdownanimation
#defineUSER_SHUTDOWNANIMATION_FILE"/data/local/shutdown.zip"
#defineSYSTEM_SHUTDOWNANIMATION_FILE"/system/media/shutdown.zip"
所以需要去overlay資源/system/media/bootanimation.zip和/system/media/shutdown.zip,下面簡單的介紹下開關機動畫zip的制作:
1)建立bootanimation文件夾;
2)在bootanimation/下添加開機圖片,圖片必須為.png格式;
3)將圖片按照start00001.pngstart00002.png......start00049.png格式命名;
4)按照個人需要將圖片按序號放在文件夾part0、part1、part2下,具體幾個partX文件夾,按照個人需求;
5)在bootanimation/下添加動畫屬性描述文件desc.txt,他用來設置動畫的像素、幀、閃爍次數、文件夾名稱,
desc.txt必須嚴格執行Makefile格式
我們看一個dest.txt:
32048015
p10part0
p00part1
32048015-->320像素寬度480像素高度15幀數
p10part-->p標識符1循環次數為10階段間隔時間為0part0對應文件夾,為第一階段動畫目錄
p00part1-->p標識符0本階段無限循環0階段間隔時間為0part1對應文件夾,為第二階段動畫
最後必須要有回車符,確保指令都已經完成。
6)開始打包,使用WinRAR壓縮工具,打包為bootanimation.zip:
需要選擇“壓縮文件格式”為.zip;
需要選擇“壓縮方式”為“存儲”。
制作完成。
11.修改狀態欄透明
狀態欄透明的屬性是在andorid4.4上面出現的新特性,不過對於狀態欄透明效果的設置要求比較高,一般是在運行內存>=512M的設備上才能運行,因為要實現狀態欄透明需要硬件加速來配合,不然動畫效果十分卡頓。修改狀態欄透明需要SystemUI與Launcher配合,才能達到效果。
1)修改SystemUI的一個屬性
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java::
publicstaticfinalbooleanHIGH_END=ActivityManager.isHighEndGfx();
//ActivityManager.isHighEndGfx()是用來判斷系統是否為大內存設備。將HIGH_END=true讓SystemUI默認為大內存設備
2)在packages/apps/Launcher2/src/com/android/launcher2/style.xml中自定義一個狀態欄透明的Theme屬性節點:
parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
true
@android:color/transparent
@null
true
在android4.4以後framewok中Theme.xml中增加了以下兩個屬性節點:
false
false
由於Marvell項目中使用的是實體按鍵,所以就只覆蓋了上面那個屬性。
3)修改packages/apps/Launcher2/src/com/android/launcher2/Launcher2.java::
@Override
protectedvoidonCreate(BundlesavedInstanceState){
if("pxa1L88H3".equals(Build.DEVICE)){//Addedbyhanhaoforbug3042520140902
setTheme(R.style.TransparentTheme);
}
}
在Launcher的onCreate方法中使用自定義屬性,或者直接在AndroidMainest.xml中通過android:theme=”@style/TransparentTheme”節點來實現。
12.去掉桌面上的Google搜索框
一般這個需求是針對使用Google原生啟動器Launcher2而言的。因為在Google原生代碼裡,有顯示GoogleSearch的代碼,主要是為了顯示Google搜索,如果有GoogleVoice還可以顯示語音搜索按鈕,針對大陸手機來說,GoogleSearch功能已經被和諧掉,所以要麼制作成百度搜索,要麼去掉。去掉Google搜索框的方法有很多。分兩步走,第一,去掉Google搜索框;第二、調整Workspace布局,去掉Google搜索框在界面上的占位。
第一、去掉Google搜索框
1.簡單粗暴式一
packages/apps/Launcher2/src/com/android/launcher2/Launcher.java::
privatebooleanupdateGlobalSearchIcon(){
finalSearchManagersearchManager=
(SearchManager)getSystemService(Context.SEARCH_SERVICE);
ComponentNameactivityName=searchManager.getGlobalSearchActivity();
if(Build.DEVICE.equals("pxa1L88H3")){
activityName=null;
}
if(activityName!=null){
//……
else{
//Wedisablebothsearchandvoicesearchwhenthereisnoglobalsearchprovider
}
}
在Launcher2進程啟動時,onCreate和onResume中會更新GlobalSearch圖標並保存在數組中,上面的修改將邏輯修改成了在設備中永遠默認沒有GlobalSearch應用,所以就走了下面的else分支,可保證桌面不顯示Google搜索框,上面是根據項目名做判斷,也可以直接這樣:
if(false&&activityName!=null){
2.簡單粗暴式二
在packages/apps/Launcher2/res/values/dimens.xml中修改節點
0dp
這樣也能保證永不顯示Google搜索框
3.修改QuickSearchBox模塊
去掉AndroidManifest.xml的下面節點:
比較可取的是1、3這兩種方法。
第二、去掉Workspace的占位
主要是微調布局,修改values/dimens.xml,按需修改適當的數值,下面是幾個親測符合ho9021項目4.3寸屏的布局
調整cellLayout的布局+調整ShortcutIcon的間距,使其整體上移
28dp
48dp
18dp
另外還可以通過設置Workspace的高度配合調整ShortcutIcon的間距也能實現:
100dp
13.在Launcher中隱藏掉某個App
在這裡所說的Launcher都是Google原生的Launcher2應用。
修改packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java::
privatevoidloadAllAppsByBatch(){
//……
apps=packageManager.queryIntentActivities(mainIntent,0);
if(DEBUG_LOADERS){
Log.d(TAG,"queryIntentActivitiestook"
+(SystemClock.uptimeMillis()-qiaTime)+"ms");
}
if(apps==null){
return;
}
//Addedforexamplecodestart
ResolveInforemoveApp=null;
for(ResolveInfoinfo:apps){
if(null!=info&&
info.activityInfo.packageName.equals("com.android.spare_parts")){
removeApp=info;
}
}
if(null!=removeApp){
apps.remove(removeApp);
}
//Addedend
N=apps.size();
//……
}
上面的代碼是在啟動器啟動時會通過一個List將各個app信息保存起來,然後再添加到桌布上,上面的代碼就是遍歷獲取到的所有的符合條件的app,過濾掉我們不想顯示的。當然該代碼可以抽取出來成一個方法,或者放入油條包中,抽象成一個static的工具。
那麼如果要隱藏掉的app比較多的時候怎麼辦?其實可以新建一個tempArrayList,將查詢信息符合反向查找條件的再add到apps中,該方法為如下patch:
14.在任務管理器“全部”中去掉某個App
任務管理器是Setting模塊下的一個功能,其實也就是“設置—應用程序—全部”。需要修改packages/apps/settings/src/com/android/settings/applications/ManageApplications.java
staticclassApplicationsAdapter::
ArrayListapplyPrefixFilter(CharSequenceprefix,
ArrayListorigEntries){
//此處設置過濾條件進行過濾篩選
if(prefix==null||prefix.length()==0){
returnorigEntries;
}else{
//……
}
}
15.修改輸入法列表、設置默認的輸入法
默認輸入法是在frameworks/base/packages/SettingsProvider/res/values/defaults.xml中的節點,只需要在.mk中去overlay即可。
com.android.inputmethod.latin/.LatinIME:com.baidu.input/.ImeService:com.baidu.input/com.baidu.input.IME
>com.baidu.input/.ImeService
其中def_enable_input_methods是要顯示到輸入法列表中的默認輸入法,可以看到這個節點中默認的有兩個輸入法,Android鍵盤和百度輸入法;
def_input_method是默認被選中的那個輸入法,可以看到這個節點中默認被選中的輸入法是百度輸入法。
com.baidu.input->在AndroidManifest.xml中的pachakename
.ImeService->在AndroidManifest.xml中的servicename
16.修改默認不鎖屏
1.在.mk下如果有屬性ro.lockscreen.disable.default=true則注釋掉;
2.OverlaySettingsProvider下的一個屬性:
frameworks/base/packages/SettingsProvider/res/values/defaults.xml:
false
因為在frameworks/base/packages/settingsprovider/src/com/android/providers/settings/DatabaseHelper.java::
if(SystemProperties.getBoolean("ro.lockscreen.disable.default",false)==true){
loadSetting(stmt,Settings.System.LOCKSCREEN_DISABLED,"1");
}else{
loadBooleanSetting(stmt,Settings.System.LOCKSCREEN_DISABLED,
R.bool.def_lockscreen_disabled);
}
如果設置了property屬性,那麼就直接設置為默認有鎖屏,忽略default.xml下的節點。
17.設置第一次開機時的默認Launcher
該需求是在Marvell的ho_9021上做的,在9021上除了Google原生Launcher之外,還預置了一個賓果桌面,那麼在第一次開機時,由於沒有設置preferredActivity這就導致在第一次開機時候首先會彈出一個選項框讓用戶選擇launcher。
這個需求是在第一次開機時,直接進入默認的Launcher,不彈出選項框,當用戶從“設置—應用—全部”,選擇正在使用的Launcher,並點擊“清除默認設置”;就能去掉Launcher的preferred屬性,當再次回到桌面,則正常彈出選項框。
該需求修改的前提是系統沒有開機向導,使用Android默認的開機向導。在Android源碼會有有個packages/apps/Provision模塊,很少有人注意到他。
從他的AndroidManifest.xml中從category可以看到他也是一個Launcher,同時他的priority=”1”說明他的優先級是最高的,也就是系統第一次啟動時,啟動的第一個Launcher就是他DefaultActivity。對這裡感興趣的同學,可以看一下這個模塊,功能非常簡單,就是僅僅在第一次開機時完成一些開機向導類的工作。
下面就步入正題,分析一下怎麼設置默認launcher,首先有兩個關鍵點:
1.設置默認Application需要加上權限:
2.需要在DefaultActivity.java的下面這段代碼之前做操作:
ComponentNamename=newComponentName(this,DefaultActivity.class);
pm.setComponentEnabledSetting(name,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
這段代碼是將ProvisionApplication從PackageManager中移除。如果在這段代碼之後操作,就會報錯,或者失敗。
設置默認Luancher:
1.獲取注冊到系統中的所有Launcher:
Intentintent=newIntent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
ListresolveInfoList=pm.queryIntentActivities(intent,0);
Tips:
在此處獲取系統中Launcher的List時不能使用pckageManager的
getHomeActivities(ListoutActivities);方法,通過這種方法會導致設置失敗,具體原因我還不太知道。
2.將Pervision從resolveInfoList中過濾掉:
intsize=resolveInfoList.size();
for(inti=0;i<size;){
finalResolveInforesolveInfo=resolveInfoList.get(i);
finalActivityInfoactivityInfo=resolveInfo.activityInfo;
if(null!=activityInfo&&activityInfo.packageName.equals(this.getPackageName())){
resolveInfoList.remove(i);
size-=1;
}else{
i++;
}
}
3.獲取要設置為默認Launcher的match(系統匹配度)
ComponentName[]set=newComponentName[size];
ComponentNamedefaultLauncher=newComponentName("com.android.bglauncher",
"com.ibingo.launcher2.Launcher");
intdefaultMatch=0;
for(inti=0;i<size;i++){
finalResolveInforesolveInfo=resolveInfoList.get(i);
finalActivityInfoactivityInfo=resolveInfo.activityInfo;
if(null==activityInfo){
continue;
}
set[i]=newComponentName(activityInfo.packageName,activityInfo.name);
if(defaultLauncher.getClassName().equals(activityInfo.name)){
defaultMatch=resolveInfo.match;
}
Slog.d(TAG,"candidatelauncher:"+resolveInfo.toString());
}
4.使用PackageManager的addPreferredActivity方法設置默認Launcher
IntentFilterfilter=newIntentFilter();
filter.addAction(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);
pm.clearPackagePreferredActivities(defaultLauncher.getPackageName());
pm.addPreferredActivity(filter,defaultMatch,set,defaultLauncher);
Slog.d(TAG,"setdefaultLaunchersuccesfully!");
我們可以看到第2、3步驟都是在為PackageManager的addPreferredActivity方法獲取參數,主要的設置preferredActivity的方法就是先清除application之前的默認屬性,然後再將該Application設置為所有符合IntentFilter條件的Applications中的默認值。
Tips:
在整個添加的代碼中需要加上try-catch保護
那麼我們再來看一下addPreferredActivity這個方法:
Filter是過濾條件,也就是Application中滿足filter的參數配置的Activity才會被操作;
Match是過濾條件filter與被操作的Application的匹配度值
Set作用是被操作的Application會在set集合中的這些Application中才有效
Activity就是被操作的Application
了解了這個方法之後,不僅是默認Launcher,我們同樣也可以從滿足一定filter條件的Applications中選擇一個,設置成默認值。
18.修改Wifi便攜式熱點的默認SSID名稱
frameworks/base/wifi/java/android/net/wifi/WifiApConfigStore.java中的
setDefaultApConfiguration(){
//……
config.SSID=mContext.getString(R.string.wifi_tether_configure_ssid_default);
//……
}
兩種方法:
1.添加String,替換資源
2.添加”ro.settings.wifi.ssid”屬性,替換為
config.SSID=SystemProperties.get("ro.settings.wifi.ssid",
mContext.getString(R.string.wifi_tether_configure_ssid_default));
19.修改WifiDirect的默認名字
1.修改”ro.settings.wifi_p2p_name=DefaultName”如果沒有該屬性,則覆蓋;
2.frameworks/base/packages/settingsprovider/src/com/android/providers/settings/
DatabaseHelper.java中添加:
loadGlobalSettings(SQLiteDatabasedb){
//……
loadSetting(stmt,Settings.Global.WIFI_P2P_DEVICE_NAME,
SystemProperties.get("ro.settings.wifi_p2p_name",""));
//……
}
3.按需修改frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pService.java中
getPersistedDeviceName(){
StringdeviceName=Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.WIFI_P2P_DEVICE_NAME);
//……
if(deviceName==null){
//按需修改此處的返回值
}
//……
}
一般情況下正常修改,第1第2步就行了,比較規范,如果再添加上第3步的修改,更加保險,邏輯緊密,無懈可擊;如果只在第3步的getPersistedDeviceName()中去操作,雖然也能達到目的,但是不嚴謹。
20.修改WIFI熱點中默認網絡SSID名稱AndroidAP
請修改frameworks/base/core/res/res/values/Strings.xml文件中的如下默認字符:
AndroidAP
修改為需要的字符串
系列一到這裡完了。