Android4.0的StatusBar和NavigationBar

來源:互聯網
上載者:User

主要是注意平板和手機之間布局的區別:
幾個關鍵的java類
SystemUIService
PhoneWindowManager
WindowManagerPolicy
PhoneStatusBar
TabletStatusBar
NavigationBar

 


    SystemUIService-->onCreate中判斷載入平板布局還是手機布局
       [java]
<SPAN style="WHITE-SPACE: pre"> </SPAN>// Pick status bar or system bar.  
       IWindowManager wm = IWindowManager.Stub.asInterface( 
               ServiceManager.getService(Context.WINDOW_SERVICE)); 
       try { 
           SERVICES[0] = wm.canStatusBarHide() 
                   ? R.string.config_statusBarComponent 
                   : R.string.config_systemBarComponent; 
       } catch (RemoteException e) { 
           Slog.w(TAG, "Failing checking whether status bar can hide", e); 
       } 

  // Pick status bar or system bar.
        IWindowManager wm = IWindowManager.Stub.asInterface(
                ServiceManager.getService(Context.WINDOW_SERVICE));
        try {
            SERVICES[0] = wm.canStatusBarHide()
                    ? R.string.config_statusBarComponent
                    : R.string.config_systemBarComponent;
        } catch (RemoteException e) {
            Slog.w(TAG, "Failing checking whether status bar can hide", e);
        }    然後在frameworks\base\packages\systemui\res\values\config.xml中
        [html] view plaincopyprint?<SPAN style="WHITE-SPACE: pre"> </SPAN><string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string> 
        <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string> 

 <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
        <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>

    然後通過類載入器載入PhoneStatusBar或者TabletStatusBar。也就是手機的狀態列還是平板的狀態列。
    判斷的關鍵就在wm.canStatusBarHide()這個方法裡面。
    我們跳過幾個類後最後跟進到PhoneWindowManager中:   
[java]
<SPAN style="WHITE-SPACE: pre"> </SPAN>public boolean canStatusBarHide() { 
            return mStatusBarCanHide; 
        } 

 public boolean canStatusBarHide() {
            return mStatusBarCanHide;
        }    mStatusBarCanHide是一個成員變數,修改它值得地方在:

     public void setInitialDisplaySize(int width, int height) {...}中。
[java]
<SPAN style="WHITE-SPACE: pre"> </SPAN>int shortSizeDp = shortSize 
                * DisplayMetrics.DENSITY_DEFAULT 
                / DisplayMetrics.DENSITY_DEVICE; 
        mStatusBarCanHide = shortSizeDp < 600; 
        mStatusBarHeight = mContext.getResources().getDimensionPixelSize( 
                mStatusBarCanHide 
                ? com.android.internal.R.dimen.status_bar_height 
                : com.android.internal.R.dimen.system_bar_height); 
 
        mHasNavigationBar = mContext.getResources().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 (! "".equals(navBarOverride)) { 
            if      (navBarOverride.equals("1")) mHasNavigationBar = false; 
            else if (navBarOverride.equals("0")) mHasNavigationBar = true; 
        } 

 int shortSizeDp = shortSize
                * DisplayMetrics.DENSITY_DEFAULT
                / DisplayMetrics.DENSITY_DEVICE;
        mStatusBarCanHide = shortSizeDp < 600;
        mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
                mStatusBarCanHide
                ? com.android.internal.R.dimen.status_bar_height
                : com.android.internal.R.dimen.system_bar_height);

        mHasNavigationBar = mContext.getResources().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 (! "".equals(navBarOverride)) {
            if      (navBarOverride.equals("1")) mHasNavigationBar = false;
            else if (navBarOverride.equals("0")) mHasNavigationBar = true;
        }

    這個方法略微有點長,繞過前面的判斷,取上面一部分來分析。大致的意思是:
    首先取shortSize,shortSize指的是螢幕最短的像素,比如1024*600,那麼值就是600。 shortSizeDp是把pix單位轉化成dip單位。  DisplayMetrics.DENSITY_DEFAULT的值是固定死的160,在更具手機的密度算出shortSizeDp。突出標記的地方就是平板和手機狀態列切換的關鍵了。只有最短螢幕dp大於600的裝置才會載入平板布局。
    剩下的代碼用來判斷底部虛擬按鍵是否顯示的關鍵。首先是去讀取frameworks\base\core\res\res\values\config.xml中config_showNavigationBar這個key,下面 SystemProperties.get("qemu.hw.mainkeys")這個屬性主要是給模擬器使用,可以直接忽略掉。
    分析完畢!

    現在如何切換平板和手機狀態列布局已經很明了了,就是讓shortSizeDp 的值>=600。以1024*600為例,因為DisplayMetrics.DENSITY_DEFAULT的值已經固定死是160,所以只要把DisplayMetrics.DENSITY_DEVICE的值<=160即可。修改螢幕密度的方法:
    /build/tools/buildinfo.sh中設定 ro.sf.lcd_density=160,
    當然MTK自己定義了一套屬性,MTK項目中可以通過這個屬性來設定,比較保險

    /mediatek/config/[Project_name]/system.prop中設定該屬性的值
如此基本大功告成。mm編譯,然後報錯。。。。
錯誤定位到TabletStatusBar的makeStatusBarView()中,代碼如下:
   [java]
<SPAN style="WHITE-SPACE: pre"> </SPAN> try { 
            // Sanity-check that someone hasn't set up the config wrong and asked for a navigation  
            // bar on a tablet that has only the system bar  
            if (mWindowManager.hasNavigationBar()) { 
                throw new RuntimeException( 
                        "Tablet device cannot show navigation bar and system bar"); 
            } 
        } catch (RemoteException ex) { 
        } 

  try {
            // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
            // bar on a tablet that has only the system bar
            if (mWindowManager.hasNavigationBar()) {
                throw new RuntimeException(
                        "Tablet device cannot show navigation bar and system bar");
            }
        } catch (RemoteException ex) {
        }

    問題很明顯,平板裝置中不需要NavigationBar,因為NavigationBar的東西已經全部合并到StatusBar裡面了。修改方法:

    frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改為false

 


囉嗦半天,其實就兩個問題:
    一。虛擬按鍵的隱藏和顯示:

     修改frameworks\base\core\res\res\values\config.xml中config_showNavigationBar


    二。狀態列平板和手機之間的切換:

    1.        /build/tools/buildinfo.sh中設定 ro.sf.lcd_density=160,
        當然MTK自己定義了一套屬性,MTK項目中可以通過這個屬性來設定,比較保險
        /mediatek/config/[Project_name]/system.prop中設定該屬性的值
  2.    frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改為false

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.