加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

android StatusBar和NavigationBar分析

(2015-12-21 14:13:56)
分类: android
android StatusBar和NavigationBar分析
整理的比较乱,希望有所帮助。

1. StatusBar和NavigationBar是什么
StatusBar是手机顶部状态栏   NavigationBar是手机底部“导航栏”,即Home,back,menu键

2. 隐藏StatusBar
frameworks/base/core/res/res/values/dimens.xml

把  25dip 修改为0dip

3. 隐藏NavigationBar
frameworks/base/packages/SystemUI/src/com/android/systemui/

statusbar/phone/PhoneStatusBar.java
在start函数中注释掉 "addNavigationBar();"
这是最最简单最粗暴的修改,一般不建议这么做,同样可以修改xml文件来实现
frameworks/base/core/res/res/values/config.xml
true//此处true即表示要显示NavigationBar,false表示不显示NavigationBar

还有另一种方法,通过属性设置
//属性设置可以写在init.rc内
setprop qemu.hw.mainkeys 0

如果同时设置xml和属性,那么以设置的属性会覆盖xml的设置,以属性设置为主

>>>下面简单此处代码的流程
1).首先在/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java$makeStatusBarView方法
try {
            boolean showNav = mWindowManagerService.hasNavigationBar();
            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
            if (showNav) {  //{}进而的代码用来设置view是否显示和对应的Listener
                mNavigationBarView =
                    (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);

                mNavigationBarView.setDisabledFlags(mDisabled);
                mNavigationBarView.setBar(this);
                mNavigationBarView.setOnVerticalChangedListener(
                        new NavigationBarView.OnVerticalChangedListener() {
                    @Override
                    public void onVerticalChanged(boolean isVertical) {
                        if (mSearchPanelView != null) {
                            mSearchPanelView.setHorizontal(isVertical);
                        }
                        mNotificationPanel.setQsScrimEnabled(!isVertical);
                    }
                });
                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
        }
2).很显示此处调用的是hasNavigationBar方法
这里通过WindowManagerService调用到PhoneWindowManager的hasNavigationBar方法
下面是mHasNavigationBar初始化的地方,现在很清楚看到为什么可以通过xml和属性修改了吧!
mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
        // Allow a system property to override this. Used by the emulator.
        // See also hasNavigationBar().
        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
        if ("1".equals(navBarOverride)) {
            mHasNavigationBar = false;
        } else if ("0".equals(navBarOverride)) {
            mHasNavigationBar = true;
        }

4. 虚拟按键是如何调用的?
NavigationBarView中包含的是KeyButtonView,我们看到的home,back,recentApp三个虚拟按键实际是都是一个KeyButtonView
当我们点击这三个按键的任意一个时,都会调用KeyButtonView的onTouchEvent方法,在onTouchEvent方法中会调用sendevent传递一个按键值、

void sendEvent(int action, int flags, long when) {
        final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
        final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
                0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);
        InputManager.getInstance().injectInputEvent(ev,
                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
    }
此处封装了一个KeyEvent对象,mCode即为按键值,在./packages/SystemUI/res/layout/navigation_bar.xml定义
back按键值是4,home按键值是3

此单独列一下recent_app按键事件处理流程
1). 在PhoneStatusBar.java的prepareNavigationBarView方法中注册一个button的listener
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
//mRecentsClickListener实现
    private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            awakenDreams();
            toggleRecentApps();
        }
    };
2. 下一步调用用父类BaseStatusBar的toggleRecentApps方法
    public void toggleRecentApps() {
        int msg = MSG_TOGGLE_RECENTS_APPS;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    }
接下来通过msg调用RecentsComponent的toggleRecents,其实此处调用的是Recents的toggleRecents方法
    @Override
    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
        if (mUseAlternateRecents) {
            // Launch the alternate recents if required
            mAlternateRecents.onToggleRecents(statusBarView);
            return;
        }
........
}
3. 接下来调用AlternateRecentsComponent的onToggleRecents方法
间接调用startAlternateRecentsActivity方法,在这里通过startActivity启动RecentsActivity
在这个Activity中调用了updateRecentsTasks方法
此处可以看到取这时取到了一个stack,stack啊包含了最近任务详细信息,并把该stacks给RecentsView
 void updateRecentsTasks(Intent launchIntent) {
    .......
        // Load all the tasks
        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
        SpaceNode root = loader.reload(this,
                Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount,
                mConfig.launchedFromHome);
        ArrayList stacks = root.getStacks();
        if (!stacks.isEmpty()) {
            mRecentsView.setTaskStacks(root.getStacks());
        }
    .......
}
相关的类还有RecentsView.java    TaskStackView.java    TaskStack.java
补充一下:
RecentsTaskLoader的reload等到的stacks本质上是调用SystemServicesProxy的getRecentTasks方法,
进而调用ActivityManagerService的getRecentTasks方法返回RecentTaskInfo列表
注:通过Log显示RecentTasks对应的缩略图存放的目录/data/system/recent_images/

4. 缩略图是在哪截取的?
那么,还有一个问题缩略图是哪哪截取的?
每一个电近的任务都保存在mRecentTasks数组中通过ActivityManager->ActivityManagerNative->ActivityManagerService
调用addAppTask方法将最近任务信息加入mRecentTasks数组,这是提供给应用的接口,可以主动加入最近任务

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有