Android M已經(jīng)發(fā)布了很久了捏境,很多新的特性也非常的吸引人,比如Doze模式可以使導(dǎo)航時(shí)間更長(zhǎng)嘀略,刷到nexus5上蕊玷,體驗(yàn)了一下確實(shí)不錯(cuò)。但是導(dǎo)航欄(虛擬按鍵)一直存在,感覺不是特別的爽。今天我們就從android M(6.0)進(jìn)行源碼的修改,使nexus5能夠方便的進(jìn)行導(dǎo)航欄的隱藏與恢復(fù)。
修改源碼前肪跋,看到了CSDN上的文章(http://blog.csdn.net/way_ping_li/article/details/45727335,記為文章A)土砂,寫的很好州既,但是寫的有些省略,整體的操作也較為復(fù)雜萝映,本文的操作步驟如下:
① 下載并編譯源碼
② 長(zhǎng)點(diǎn)擊隱藏導(dǎo)航欄
③ 上滑顯示導(dǎo)航欄
④ 編譯部分修改代碼吴叶,重新生成system.img
文章A的整體思路是在導(dǎo)航欄上添加了一個(gè)圖標(biāo)按鈕,點(diǎn)擊后隱藏導(dǎo)航欄锌俱,上滑顯示導(dǎo)航欄晤郑。首先說一下隱藏導(dǎo)航欄,感覺官方的導(dǎo)航欄還是很完美的贸宏,所以不打算添加任何元素造寝,這里對(duì)任務(wù)鍵(虛擬正方形按鍵)進(jìn)行長(zhǎng)點(diǎn)擊操作進(jìn)行修改;之后通過上滑來顯示導(dǎo)航欄吭练,文章A的思路是通過各種系統(tǒng)內(nèi)的很多回調(diào)與消息的傳遞完成的诫龙,改動(dòng)幅度蠻大的,自己嘗試按照文章中的進(jìn)行修改鲫咽,需要對(duì)文章A中提到的部分進(jìn)行修改外签赃,還需對(duì)部分aidl以及與此相關(guān)的類進(jìn)行修改等,比較的繁瑣分尸,當(dāng)然最后實(shí)現(xiàn)了上滑顯示锦聊,本文將通過廣播來進(jìn)行上滑操作的傳遞。
下載并編譯源碼
源碼的下載編譯可以參考google官方教程https://source.android.com/source/downloading.html,本文編譯的源碼分支android-6.0.1_r50箩绍。
nexus5源碼下載后需要下載驅(qū)動(dòng)https://developers.google.com/android/nexus/drivers孔庭,解壓到根目錄后執(zhí)行,執(zhí)行后產(chǎn)生vendor目錄,之后編譯代碼
源碼編譯完成后圆到,之后的framework的修改不用再次重新編譯怎抛,只需使用mmm命令編譯部分模塊即可,最后使用make snod生成system.img,刷進(jìn)手機(jī)即可芽淡。
修改framework后生成的system.img,在進(jìn)行刷機(jī)時(shí)僅僅刷進(jìn)system.img即可马绝,首次刷機(jī)盡量把userdata.img, boot.img都進(jìn)行刷入。
長(zhǎng)點(diǎn)擊隱藏導(dǎo)航欄
虛擬按鍵有3個(gè)挣菲,考慮到返回鍵一般有一定的作用富稻,于是修改任務(wù)鍵(虛擬正方形按鍵)的長(zhǎng)點(diǎn)擊事件,使其在長(zhǎng)點(diǎn)擊后可以隱藏導(dǎo)航欄己单。
./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
private void prepareNavigationBarView() {
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
mNavigationBarView.getRecentsButton().setLongClickable(true);
//去除長(zhǎng)點(diǎn)擊操作
//mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
mNavigationBarView.getBackButton().setLongClickable(true);
mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
//添加長(zhǎng)點(diǎn)擊操作唉窃,長(zhǎng)點(diǎn)擊進(jìn)行導(dǎo)航欄的刪除
mNavigationBarView.getRecentsButton().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mWindowManager.removeView(mNavigationBarView);
mNavigationBarView = null ;
//isNavigationShow用于記錄當(dāng)前導(dǎo)航欄狀態(tài),定義在PhoneStatusBar的全局變量中
isNavigationShow = false ;
Log.d("===>LYD", "remove navigation bar");
return true;
}
});
mAssistManager.onConfigurationChanged();
}
此時(shí)進(jìn)行長(zhǎng)點(diǎn)擊任務(wù)鍵將隱藏導(dǎo)航欄纹笼。
上滑顯示導(dǎo)航欄
上滑顯示導(dǎo)航欄借鑒了文章A中的一些技巧,在系統(tǒng)上滑時(shí)會(huì)回調(diào)./frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java的修改主要是實(shí)現(xiàn)onSwipeFromBottom(豎屏?xí)r)和onSwipeFromRight(橫屏?xí)r)兩個(gè)接口苟跪,在此兩接口內(nèi)發(fā)送廣播廷痘。
./frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
// monitor for system gestures
mSystemGestures = new SystemGesturesPointerEventListener(context,
new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
}
@Override
public void onSwipeFromBottom() {
if (mNavigationBar != null && mNavigationBarOnBottom) {
requestTransientBars(mNavigationBar);
}
//開始發(fā)送廣播
Intent intent = new Intent();
intent.setAction("LYD_SHOW_NAVIGATION_BAR");
mContext.sendBroadcast(intent);
}
@Override
public void onSwipeFromRight() {
if (mNavigationBar != null && !mNavigationBarOnBottom) {
requestTransientBars(mNavigationBar);
}
//開始發(fā)送廣播
Intent intent = new Intent();
intent.setAction("LYD_SHOW_NAVIGATION_BAR");
mContext.sendBroadcast(intent);
}
//省略后續(xù)代碼
下面我們需要做的是在之前的PhoneStatusBar中對(duì)廣播進(jìn)行處理,將狀態(tài)欄添加到windowManager中件已。
@Override
public void start() {
//省略代碼笋额,在此方法末尾動(dòng)態(tài)注冊(cè)廣播監(jiān)聽器
IntentFilter filter = new IntentFilter();
filter.addAction("LYD_SHOW_NAVIGATION_BAR");
mContext.registerReceiver(navBarBroadcastReceiver, filter);
}
private BroadcastReceiver navBarBroadcastReceiver = new LydShowNavigationBarBroadcast();
private static boolean isNavigationShow = true ;
//自定義廣播
class LydShowNavigationBarBroadcast extends BroadcastReceiver{
public LydShowNavigationBarBroadcast() {
super();
}
@Override
public void onReceive(Context context, Intent intent) {
Log.d("====>LYD", "receiver show navigation bar broadcast");
//防止多次被添加
if(isNavigationShow){
return ;
}
showNavigationBar();
}
@Override
public IBinder peekService(Context myContext, Intent service) {
return super.peekService(myContext, service);
}
}
//展示導(dǎo)航欄
public void showNavigationBar() {
mNavigationBarView =(NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null);
mNavigationBarView.setBar(this);
prepareNavigationBarView();
addNavigationBar();
isNavigationShow = true;
//防止在桌面時(shí)上拉出導(dǎo)航欄時(shí),導(dǎo)航欄背景為黑色
mNavigationBarView.setBackgroundColor(Color.TRANSPARENT);
Log.d("===>LYD", "show navigation");
}
注意導(dǎo)入android.graphics.Color類
代碼到此就修改完了篷扩,下面我們只需要對(duì)相應(yīng)模塊進(jìn)行編譯就行了兄猩。
編譯部分修改代碼,重新生成system.img
-
①切換到源代碼目錄鉴未,運(yùn)行
source build/envsetup.sh //初始化環(huán)境變量 lunch //切換編譯平臺(tái)
-
②編譯PhoneWindowManager.java所在模塊(core)
mmm ./frameworks/base/services/core/ mmm ./frameworks/base/services/
-
③編譯PhoneStatusBar.java所在模塊(SystemUI)
mmm ./frameworks/base/packages/SystemUI/
-
④生成system.img.
make snod
-
⑤刷入system.img
adb reboot bootloader fastboot flash system system.img
這樣一個(gè)定制過導(dǎo)航欄的nexus5(hammerhead)系統(tǒng)已經(jīng)制作完成了枢冤。
效果
解決了導(dǎo)航欄的隱藏與浮現(xiàn),終于可以不用一直看著不搭配的導(dǎo)航欄了铜秆。下面是隱藏前后QQ音樂的截圖:
后記
能夠給該功能在設(shè)置中加一個(gè)開關(guān)就完美了淹真,快來查看Android導(dǎo)航欄隱藏與浮現(xiàn)(二)吧。
由于筆者一般都是使用手機(jī)都是豎屏的连茧,為了減少誤操作核蘸,所以僅僅上滑時(shí)(swipeFromBottom)才顯示導(dǎo)航欄,從右側(cè)滑動(dòng)(swipeFromRight)不觸發(fā)操作啸驯。
刷機(jī)有風(fēng)險(xiǎn)客扎,大家需謹(jǐn)慎,本文僅僅是提供一種思想,刷機(jī)造成的問題與本文以及作者無關(guān)罚斗。