最近工作中的UI设计需要将android的状态栏移动到底部,为了改这个东西,需要把SystemUI的流程大概了解一番,对照源码看了一下,也查阅了相关资料,讲自己所学习的记录下来android 4.0 中将 状态栏的独立成了一个应用,代码位置在/android/frameworks/base/packages/SystemUI下,在主xml文件中,有这样一段代码
<!-- Broadcast receiver that gets the broadcast at boot time and starts
up everything else.
TODO: Should have an android:permission attribute
-->
<service android:name="SystemUIService"
android:exported="true"
/>
从注释可以看到:应用在开机启动的时候启动这个SystemUIService服务,在服务起来的时候,onCreate方法中有这样一段代码
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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中的canStatusBarHide这个方法决定的,如果canStatusBarHide()返回true则系统加载手机模式(R.string.config_statusBarComponent)时候的布局,false则为平板模式(R.string.config_systemBarComponent)。
判断完成之后,我们则开始启动对应的服务
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();
}
我们的机器所使用的分辨率匹配为手机模式,所以启动的对象为 com.android.systemui.statusbar.phone.PhoneStatusBar
PhoneStatusBar的是继承自抽象类StatusBar, 我们暂时将目光放在他的父类上,因为父类中实现一个start()方法,是加载PhoneStatusBar的入口。在这个方法中,大概就是对通知状态已经状态栏以及一些状态和状态更新的回调类进行初始化,并使用makeStatusBarView()方法创建状态栏的视图,makeStatusBarView()是在子类PhoneStatusBar中具体实现的,实际上,我们看到的状态栏(包括上面规则的一块长方形,下拉列表)是由三个视图组成的,顶上的视图,叫做PhoneStatusBarView,它的布局实现在status_bar.xml中,
<com.android.systemui.statusbar.phone.PhoneStatusBarView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:background="@drawable/status_bar_background"
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
>
<LinearLayout android:id="@+id/icons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:orientation="horizontal"
>
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
>
<com.android.systemui.statusbar.StatusBarIconView android:id="@+id/moreIcon"
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="match_parent"
android:src="@drawable/stat_notify_more"
android:visibility="gone"
/>
<com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:gravity="center_vertical"
android:orientation="horizontal"/>
</LinearLayout>
<LinearLayout android:id="@+id/statusIcons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"/>
<LinearLayout
android:id="@+id/signal_battery_cluster"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="2dp"
android:orientation="horizontal"
android:gravity="center"
>
<include layout="@layout/signal_cluster_view"
android:id="@+id/signal_cluster"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/battery"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="4dip"
/>
</LinearLayout>
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:singleLine="true"
android:paddingLeft="6dip"
android:gravity="center_vertical|left"
/>
</LinearLayout>
<LinearLayout android:id="@+id/ticker"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="6dip"
android:animationCache="false"
android:orientation="horizontal" >
<ImageSwitcher android:id="@+id/tickerIcon"
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="@dimen/status_bar_icon_size"
android:layout_marginRight="4dip"
>
<com.android.systemui.statusbar.AnimatedImageView
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="@dimen/status_bar_icon_size"
android:scaleType="center"
/>
<com.android.systemui.statusbar.AnimatedImageView
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="@dimen/status_bar_icon_size"
android:scaleType="center"
/>
</ImageSwitcher>
<com.android.systemui.statusbar.phone.TickerView android:id="@+id/tickerText"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingRight="10dip">
<TextView
android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
/>
<TextView
android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
/>
</com.android.systemui.statusbar.phone.TickerView>
</LinearLayout>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
PhoneStatusBarView本身是一个框架布局,从xml文件里面的控件ID命名,都知道这个控件代表的是放的什么图标。我见过有的机器需要在状态栏上加HOME,MENU,BACK三个图标,可以在这个status_bar中加上,不过要注意处理点击事件的传递,不然就会点击按钮的时候,下拉菜单会出来。比如我的就是左边一个HOME,MENU右边BACK 在800*480的屏幕上,PhoneStatusBarView.java中的onInterceptTouchEvent方法里面判断,
@Override
public boolean onInterceptTouchEvent(MotionEvent event)
if(event.getX() > 260 && event.getX() < 672){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mButtonBounds.contains((int)event.getX(), (int)event.getY())) {
mCapturingEvents = false;
return false;
}
}
mCapturingEvents = true;
return mService.interceptTouchEvent(event) ? true : super.onInterceptTouchEvent(event);
}else{
return false;
}
}