android StatusBar和NavigationBar分析

android StatusBar和NavigationBar分析

整理的比較亂,希望有所幫助。


1. StatusBar和NavigationBar是什麼
StatusBar是手機頂部狀態欄   NavigationBar是手機底部“導航欄”,即Home,back,menu鍵

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

把  <dimen name="status_bar_height">25dip</dimen> 修改爲<dimen name="status_bar_height">0dip</dimen>

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
<bool name="config_showNavigationBar">true</bool>//此處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<TaskStack> 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數組,這是提供給應用的接口,可以主動加入最近任務

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章