在启动的时候,在
PhoneStatusBar的
start()方法中,注册了广播监听,用来显示、隐藏NavigationBar.
|
对相应的广播做处理。比如addNavbar()、removeView等操作。
private BroadcastReceiver mNavBarStatuReceiver=new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null) {
mNavBarStatuAction = intent.getAction();
mHandler.removeCallbacks(showNavBarRunnable);
mHandler.postDelayed(showNavBarRunnable, 300);
}
}
};
private Runnable showNavBarRunnable = new Runnable() {
public void run() {
synchronized (mQueueLock2) {
if (ACTION_DISPLAY_NAV_BAR.equals(mNavBarStatuAction)) {
try {
if (mNavigationBarView == null) {
addNavBar();
}
if (mNavigationBarView != null) {
checkBarMode(MODE_TRANSPARENT,
mNavigationBarWindowState, mNavigationBarView.getBarTransitions(), false);
}
} catch (Exception e) {
}
if (ACTION_HIDE_NAV_BAR.equals(mNavBarStatuAction)) {
if (mNavigationBarView != null) {
mWindowManager.removeView(mNavigationBarView);
}
try {
mWindowManagerService.setHasNavigationBar(false);
} catch (RemoteException ex) {
}
mNavigationBarView = null;
}
}
}
};
|
现在对addNavBar做简单分析:
看代码就明白了,其实很简单。只是new一个view添加到
WindowManager
中去。仅此而已。
private void addNavBar() {
if (mNavigationBarView == null) {mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null); mNavigationBarView.setDisabledFlags(mDisabled1); mNavigationBarView.setBar(this); prepareNavigationBarView();
}
mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}
|
最主要是这段代码并没有说把NavigationBar添加到屏幕的下方。继续看getNavigationBarLayoutParams()方法
private WindowManager.LayoutParams getNavigationBarLayoutParams() {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
0
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
// this will allow the navbar to run in an overlay on devices that support this
if (ActivityManager.isHighEndGfx()) {
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
lp.setTitle("NavigationBar");
lp.windowAnimations = 0;
return lp;
}
|
这里设置了LayoutParams,其中主要是设置了Type:WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,这是在WindowManager的LayoutParams中定义的值。
绘制界面的时候在
PhoneWindowManager中的
layoutWindowLw方法中进行判断Type:
else if (attrs.type == TYPE_NAVIGATION_BAR 4205 || attrs.type == TYPE_NAVIGATION_BAR_PANEL) { 4206 // The navigation bar has Real Ultimate Power. 4207 pf.left = df.left = of.left = mUnrestrictedScreenLeft; 4208 pf.top = df.top = of.top = mUnrestrictedScreenTop; 4209 pf.right = df.right = of.right = mUnrestrictedScreenLeft 4210 + mUnrestrictedScreenWidth; 4211 pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop 4212 + mUnrestrictedScreenHeight; 4213 if (DEBUG_LAYOUT) Slog.v(TAG, String.format( 4214 "Laying out navigation bar window: (%d,%d - %d,%d)", 4215 pf.left, pf.top, pf.right, pf.bottom)); 4216 } |
在这里进行了具体的位置设置,大概意思是把
TYPE_NAVIGATION_BAR_PANEL类型的位置参数设置在屏幕底部。
那么问题来了。是在哪里发的ACTION_DISPLAY_NAV_BAR和ACTION_HIDE_NAV_BAR广播呢?是openGrok上搜索发现,这两个广播在原生系统AOSP里面是没有的,而是三方加的。
在我们的项目中,是客户自己添加的。如下:
@Override149 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 150 if (preference == mShowNavbar) { 151 boolean value = mShowNavbar.isChecked(); 152 Intent shoNavBarIntent = new Intent(value ? ACTION_SHOW_NAVBAR : ACTION_HIDE_NAVBAR); 153 getActivity().sendBroadcast(shoNavBarIntent); 154 Settings.System.putInt(getContentResolver(), SHOW_NAVBAR, value ? 1 : 0); 155 return true; 156 }//......} |
在
BqDisplaySettings.java中添加了一个选项开关,用来控制是否显示虚拟按键,打开或者关闭开关发送相应的广播,然后PhoneStatusBar.java接受广播并处理广播。
到这里NavigationBar的显示和隐藏功能大概讲解完了。