在如何控制android系统中NavigationBar 的显示与隐藏文章里扼要地介绍了Navigationbar的背景知识,
NavigationBar的代码是放在...frameworksasepackagesSystemUI路径下面的。该路径下的工程主要负责手机中系统级UI的显示部份,以下图框当选中部份(包括其中的通知栏的显示),USB的连接,截屏等等。
NavigationBar的创建
navigationbar 的代码是在SystemUI工程SystemUI/src/com/android/systemui/statusbar/phone的路径下,其中navigationbar是由PhoneStatusBar.java类创建的。在该类的makeStatusBarView()方法下,可以看到创建Navigationbar的进程:
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
/// M: Support Smartbook Feature.
if (true) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
mNavigationBarView =
(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
mNavigationBarView.setDisabledFlags(mDisabled);
mNavigationBarView.setBar(this);
mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
checkUserAutohide(v, event);
return false;
}});
}
} catch (RemoteException ex) {
// no window manager? good luck with that
}
WindowManagerService通过判断是不是需要显示NavigationBar来决定是不是需要创建NavigationBarView, NavigationBarView即为我们看到视图的view了,navigation_bar即为NavigationBarView实例化的layout,你可以在SystemUI工程下的layout文件夹下找到。
通过修改navigation_bar布局的方式来自定义NavigationBar的UI。在该layout文件中有这样1个类。com.android.systemui.statusbar.policy.KeyButtonView,它是系统定义的在NavigationBar上的按钮类(后面会讲到),点击会产生波纹的效果。
NavigationBarView主负责UI的初始化工作,实例化布局,根据屏幕方向先取正确的图片。
NavigationBar按钮的事件绑定
NavigationBar按钮上的事件绑定其实不是在NavigationBarView里实现,而是在SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java类中完成的。
通过NavigationBarView对外提供的获得按钮接口来完成按钮的绑定:
Recent, Home, SearchLight按钮事件的绑定
private void prepareNavigationBarView() {
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}
Menu, Home, Back按钮事件的绑定:
上面3个按钮都是KeyButtonView类,它们的事件响应进程都是在类本身里面完成的。它们通过onTouchEvent()方法来响应点击事件,
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
int x, y;
switch (action) {
case MotionEvent.ACTION_DOWN:
//Slog.d("KeyButtonView", "press");
mDownTime = SystemClock.uptimeMillis();
setPressed(true);
if (mCode != 0) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
} else {
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
}
break;
case MotionEvent.ACTION_MOVE:
x = (int)ev.getX();
y = (int)ev.getY();
setPressed(x >= -mTouchSlop
&& x < getWidth() + mTouchSlop
&& y >= -mTouchSlop
&& y < getHeight() + mTouchSlop);
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
if (mCode != 0) {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
}
break;
case MotionEvent.ACTION_UP:
final boolean doIt = isPressed();
setPressed(false);
if (mCode != 0) {
if (doIt) {
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
playSoundEffect(SoundEffectConstants.CLICK);
} else {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
} else {
// no key code, just a regular ImageView
if (doIt) {
performClick();
}
}
if (mSupportsLongpress) {
removeCallbacks(mCheckLongPress);
}
break;
}
return true;
}
mCode是用来判断该触摸是来自于哪一个button,表示不同button的keycode在KeyEvent中类都有定义。该值在布局文件中通过获得navigationbar_view中的systemui:keycode属性来取得,下面是layout布局文件中back相应代码段:
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_back"
systemui:keyCode="4"
android:layout_weight="0"
android:scaleType="center"
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/
accessibility_back"
/>
在onTouch中方法通过sendEvent()方法来履行不同的keycode响应事件,该方法会创建1个包括keycode的KeyEvent对象封装,然后通过injectInputEvent()向InputManager插入1个事件,再发送出去。