把android 4.2平板的状态栏从底部挪到顶部 NavigationBar

来源:互联网 发布:大数据 智能交通 编辑:程序博客网 时间:2024/05/01 15:05

没在网上搜到相关文章,只能自己动手丰衣足食了,留下足迹以给后来人参考


需要修改的文件:

1、frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\TabletStatusBar.java 

把该文件中类似 Gravity.BOTTOM  都改为  Gravity.TOP

2、frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java

这个文件很重要,很多需要隐藏状态栏的大大们都没有想到隐藏个状态栏还需要改这个东西,造成出现问题:状态栏是隐藏了,可是底部还是有一个黑色条

这个黑色的条其实就是状态栏的位置了

函数 beginLayoutLw

if (mNavigationBarOnBottom) {                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;                    if (navVisible) {                        mNavigationBar.showLw(true);                        mDockBottom = mTmpNavigationFrame.top;                        mRestrictedScreenHeight = mDockBottom - mDockTop;                    } else {                        // We currently want to hide the navigation UI.                        mNavigationBar.hideLw(true);                    }                    if (navVisible && !mNavigationBar.isAnimatingLw()) {                        // If the nav bar is currently requested to be visible,                        // and not in the process of animating on or off, then                        // we can tell the app that it is covered by it.                        mSystemBottom = mTmpNavigationFrame.top;                    }
-》

             if (mNavigationBarOnBottom) {                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];             if (DEBUG_LAYOUT) Log.i(TAG, "mStatusBarHeight: " + mStatusBarHeight+ "   mNavBarHeight:"+mNavBarHeight);                    mTmpNavigationFrame.set(0, 0, displayWidth, mNavBarHeight);                    mStableTop = mStableFullscreenTop = mTmpNavigationFrame.bottom;                    if (navVisible) {                        mNavigationBar.showLw(true);                        mDockTop = mTmpNavigationFrame.bottom;                        mRestrictedScreenHeight = mDockBottom - mDockTop;     mRestrictedScreenTop = mNavBarHeight;                     } else {                        // We currently want to hide the navigation UI.                        mNavigationBar.hideLw(true);                    }                    if (navVisible && !mNavigationBar.isAnimatingLw()) {                        // If the nav bar is currently requested to be visible,                        // and not in the process of animating on or off, then                        // we can tell the app that it is covered by it.                        mSystemTop = mTmpNavigationFrame.bottom;

其中

mNavBarHeight 是新增的变量可以通过以下方法初始化
mNavBarHeight = mContext.getResources().getDimensionPixelSize(
        com.android.internal.R.dimen.navigation_bar_height);


3、frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\NotificationPanel.java   

修改内部类 Choreographer的方法createAnimation     这处修改是为点击notification区域的弹出和隐藏动画的,修改前是向底部隐藏从底部出现,修改后是向顶部隐藏从顶部出现

            if (appearing) {                // we want to go from near-the-top to the top, unless we're half-open in the right                // general vicinity                end = 0;                if (mNotificationCount == 0) {                    end += mContentFrameMissingTranslation;                }                start = HYPERSPACE_OFFRAMP+end;            } else {                start = y;                end = y + HYPERSPACE_OFFRAMP;            }

-》

            if (appearing) {                // we want to go from near-the-top to the top, unless we're half-open in the right                // general vicinity                end = 0;                if (mNotificationCount == 0) {                    end += mContentFrameMissingTranslation;                }                start = - HYPERSPACE_OFFRAMP;            } else {                start = y;                 end = y - HYPERSPACE_OFFRAMP;           }

4、frameworks\base\core\java\android\view\ViewRootImpl.java    这个是为了修改bug: 把状态栏从底部移动到顶部 隐藏状态栏后无法再显示状态栏

                if(e1.getY()>dm.heightPixels-GESTURE_AREA_HEIGHT){                    float y = e1.getY()-e2.getY();
->

                if(e1.getY()<GESTURE_AREA_HEIGHT){                    float y = e2.getY()-e1.getY();


5、xml文件

Index: styles.xml===================================================================--- styles.xml(revision 16)+++ styles.xml(revision 15)@@ -129,16 +129,15 @@     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />      <style name="Animation" />-    +     <style name="Animation.ShirtPocketPanel">-        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in</item>-        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out</item>+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>     </style>      <style name="Animation.RecentPanel">-        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in</item>-        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out</item>+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>     </style>      <!-- Standard animations for hiding and showing the status bar. -->@@ -169,7 +168,7 @@     <style name="ClingTitleText">         <item name="android:layout_width">wrap_content</item>         <item name="android:layout_height">wrap_content</item>-        <item name="android:layout_marginTop">5dp</item>+        <item name="android:layout_marginBottom">5dp</item>         <item name="android:textSize">23sp</item>         <item name="android:textColor">#49C0EC</item>         <item name="android:shadowColor">#000000</item>Index: system_bar_notification_panel.xml===================================================================--- system_bar_notification_panel.xml(revision 16)+++ system_bar_notification_panel.xml(revision 15)@@ -21,16 +21,16 @@     android:id="@+id/content_parent"     android:layout_height="match_parent"     android:layout_width="match_parent"-    android:gravity="right|top"+    android:gravity="right"     >      <!-- lift the panel up off the status bar while leaving a touchable are -->     <Space         android:id="@+id/system_bar_notification_panel_bottom_space"-        android:layout_height="50dp"+        android:layout_height="56dp"         android:layout_width="478dp"         android:layout_alignParentRight="true"-        android:layout_alignParentTop="true"+        android:layout_alignParentBottom="true"         />      <LinearLayout@@ -40,8 +40,8 @@         android:layout_width="478dp"         android:orientation="vertical"         android:layout_alignParentRight="true"-        android:layout_below="@id/system_bar_notification_panel_bottom_space"-        android:paddingTop="8dp"+        android:layout_above="@id/system_bar_notification_panel_bottom_space"+        android:paddingBottom="8dp"         >          <include layout="@layout/system_bar_notification_panel_title"Index: system_bar.xml===================================================================--- system_bar.xml(revision 16)+++ system_bar.xml(revision 15)@@ -23,12 +23,11 @@     android:background="@drawable/system_bar_background"     >          <FrameLayout         android:id="@+id/bar_contents_holder"         android:layout_width="match_parent"         android:layout_height="@*android:dimen/system_bar_height"-        android:layout_gravity="top"+        android:layout_gravity="bottom"         >         <RelativeLayout             android:id="@+id/bar_contents"@@ -136,7 +135,7 @@         android:id="@+id/bar_shadow_holder"         android:layout_width="match_parent"         android:layout_height="@*android:dimen/system_bar_height"-        android:layout_gravity="top"+        android:layout_gravity="bottom"         >         <!-- lights out shade -->         <RelativeLayout@@ -152,7 +151,7 @@                 android:layout_height="48dip"                 android:src="@drawable/ic_sysbar_lights_out_dot_small"                 android:layout_alignParentLeft="true"-                android:layout_alignParentTop="true"+                android:layout_alignParentBottom="true"                 />             <ImageView                 android:id="@+id/dot1"@@ -160,7 +159,7 @@                 android:layout_height="48dip"                 android:src="@drawable/ic_sysbar_lights_out_dot_large"                 android:layout_toRightOf="@+id/dot0"-                android:layout_alignParentTop="true"+                android:layout_alignParentBottom="true"                 />             <ImageView                 android:id="@+id/dot2"@@ -168,7 +167,7 @@                 android:layout_height="48dip"                 android:src="@drawable/ic_sysbar_lights_out_dot_small"                 android:layout_toRightOf="@+id/dot1"-                android:layout_alignParentTop="true"+                android:layout_alignParentBottom="true"                 />             <ImageView                 android:id="@+id/dot3"@@ -176,7 +175,7 @@                 android:layout_height="48dip"                 android:src="@drawable/ic_sysbar_lights_out_dot_small"                 android:layout_alignParentRight="true"-                android:layout_alignParentTop="true"+                android:layout_alignParentBottom="true"                 />         </RelativeLayout>     </FrameLayout>


以下内容转自 : http://blog.csdn.net/yunnywu/article/details/7629760


android4.0系统可以运行于平板电脑和手机上面,这样对于状态栏来说,也是有不同风格的,从SystemUi的代码分类我就可以看出来,google考虑了不同情况下状态栏的显示等,

在源代码里面有这么两个文件夹需要注意:

com.android.systemui.statusbar.phone  这个是针对手机而需要的status bar

com.android.systemui.statusbar.tablet   这个是针对平板电脑而需要的staus bar(system bar)

 

首先状态栏是如何启动起来的呢?

我们都知道系统刚启动,在SystemServer会加载系统的各种服务,状态栏也不例外,就是在这个时候创建的,代码如下:

SystemServer.java

 ActivityManagerService.self().systemReady(new Runnable() {
            public void run() {
                Slog.i(TAG, "Making services ready");

                startSystemUi(contextF);
                try {
                    if (batteryF != null) batteryF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Battery Service ready", e);
                }

 

static final void startSystemUi(Context context) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        Slog.d(TAG, "Starting service: " + intent);
        context.startService(intent);
    }

 

通过上面的代码我就看到系统启动了com.android.systemui.SystemUIService 这个服务,在这个服务里面就会启动状态栏,

但是这里就会有个选择,是启动status bar呢 还是启动 system bar呢,android是这么决定的:

public void onCreate() {
        // Pick status bar or system bar.
        IWindowManager wm = IWindowManager.Stub.asInterface(
                ServiceManager.getService(Context.WINDOW_SERVICE));
        try {
            SERVICES[0] = wm.canStatusBarHide()  (1)
                    ? R.string.config_statusBarComponent(2)
                    : R.string.config_systemBarComponent;(3)
        } catch (RemoteException e) {
            Slog.w(TAG, "Failing checking whether status bar can hide", e);
        }

        final int N = SERVICES.length;
        mServices = new SystemUI[N];
        for (int i=0; i<N; i++) {
            Class cl = chooseClass(SERVICES[i]);
            Slog.d(TAG, "loading: " + cl);
            try {
                mServices[i] = (SystemUI)cl.newInstance();
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InstantiationException ex) {
                throw new RuntimeException(ex);
            }
            mServices[i].mContext = this;
            Slog.d(TAG, "running: " + mServices[i]);
            mServices[i].start();
        }
    }

 

上面的(1) 出,会调用到phoneWIndowManager里面对应的那个函数,在那里面会根据配置文件,手机宽高等信息来判断使用哪一种bar,代码如下

public boolean canStatusBarHide() {
        return mStatusBarCanHide;
    }

 if (width > height) {
            shortSize = height;
          .........

        } else {
            shortSize = width;
          .......

        }

        // Determine whether the status bar can hide based on the size
        // of the screen.  We assume sizes > 600dp are tablets where we
        // will use the system bar.
        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);

 

这里假如手机宽(高) 小于600dp,就认为是手机了,这样mStatusBarHide = true;

我们回到这里

SERVICES[0] = wm.canStatusBarHide()  

                    ? R.string.config_statusBarComponent;

                    : R.string.config_systemBarComponent;

这样SERVICES[0]  = R.string.config_statusBarComponent (这个字符串就是 com.anroid.systemui.statusbar.phone)

实际上SERVERCES这个数组里面就两个元素,一个是我们上面的那个com.anroid.systemui.statusbar.phone ,另外一个是PowerUI,这个暂且不管,这个主要是根据电量等信息弹出一些提示框,比如电量低,或者充电器有问题等框。

接下来会调用com.anroid.systemui.statusbar.phone的start方法,注意com.anroid.systemui.statusbar.phone这个类不是一个服务,就是一个普通的类,start方法也是它的一个普通的方法而已。

在start方法里面就会创建状态栏那些界面对应的各种view,包括下拉状态栏后的view等,把这些view都创建好以后,就把这个view加载windowmanager里面就可以了,这样状态栏就可以显示出来了,代码如下:

 

final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                height,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                PixelFormat.OPAQUE);
        
        // the status bar should be in an overlay if possible
        final Display defaultDisplay 
            = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                .getDefaultDisplay();
        if (ActivityManager.isHighEndGfx(defaultDisplay)) {
            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }

        lp.gravity = getStatusBarGravity();
        lp.setTitle("StatusBar");
        lp.packageName = mContext.getPackageName();
        lp.windowAnimations = R.style.Animation_StatusBar;
        WindowManagerImpl.getDefault().addView(sb, lp);  //这里的sb就是状态栏view

 

这里需要注意的是 平时看到的状态栏和下拉后的状态栏是两个东西,不要混到一起,而且这里也会创建两个view,一个是普通的状态栏view,另外一个下拉后的view,这两个view都要加载WindosManager里面,添加的代码基本一样,但是最重要的是那个参数里面的type是不一样的,一个是WindowManager.LayoutParams.TYPE_STATUS_BAR,而下拉的那个type是WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;