根据上上一篇文章,我这里知道,SystemServer会通过 SystemUIService,SystemUIApplication类来 通过反射的方式将继承了SystemUI的各个子服务类实例化 , 其中我们可以看到:
<item>com.android.systemui.SystemBarsitem>
这就是我们今天的主角了。
SystemBars 里面的代码并不多,可谓是一目了然,如下:
/**
* Ensure a single status bar service implementation is running at all times, using the in-process implementation according to the product config.
根据产品配置使用进程内实现,确保始终运行单个状态栏服务实现。
*/
public class SystemBars extends SystemUI {
private static final String TAG = "SystemBars";
private static final boolean DEBUG = false;
private static final int WAIT_FOR_BARS_TO_DIE = 500;
// in-process fallback implementation, per the product config 根据产品配置 进程内回退实现
private SystemUI mStatusBar;
@Override
public void start() {
if (DEBUG) Log.d(TAG, "start");
createStatusBarFromConfig();
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mStatusBar != null) {
mStatusBar.dump(fd, pw, args);
}
}
private void createStatusBarFromConfig() {
if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
final String clsName = mContext.getString(R.string.config_statusBarComponent);
if (clsName == null || clsName.length() == 0) {
throw andLog("No status bar component configured", null);
}
Class<?> cls = null;
try {
cls = mContext.getClassLoader().loadClass(clsName);
} catch (Throwable t) {
throw andLog("Error loading status bar component: " + clsName, t);
}
try {
mStatusBar = (SystemUI) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
mStatusBar.start();
if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}
private RuntimeException andLog(String msg, Throwable t) {
Log.w(TAG, msg, t);
throw new RuntimeException(msg, t);
}
}
看看 frameworks\base\packages\SystemUI\res\values 路径下的config.xml文件,搜索里面的config_statusBarComponent,可以得到:
<string name="config_statusBarComponent" translatable="false">
com.android.systemui.statusbar.phone.StatusBarstring>
好吧,我们需要来到我们的下一站:StatusBar
StatusBar 也继承了SystemUI
这里来看下start方法
@Override
public void start() {
mGroupManager = Dependency.get(NotificationGroupManager.class);
...
mNotificationLogger = Dependency.get(NotificationLogger.class);
...
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
...
// 1. 获取服务端信息
// 1.1 获取StatusBarManagerService的服务端代理对象
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
...
// 1.2 为CommandQueue对象添加回调
mCommandQueue = getComponent(CommandQueue.class);
mCommandQueue.addCallbacks(this);
int[] switches = new int[9];
ArrayList<IBinder> binders = new ArrayList<>();
ArrayList<String> iconSlots = new ArrayList<>();
ArrayList<StatusBarIcon> icons = new ArrayList<>();
Rect fullscreenStackBounds = new Rect();
Rect dockedStackBounds = new Rect();
try {
// 1.3 从StatusBarManagerService获取信息
mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
fullscreenStackBounds, dockedStackBounds);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
// 2. 创建视图,并添加到窗口中
createAndAddWindows();
// Make sure we always have the most current wallpaper info.
//确保我们总是有最新的壁纸信息。
IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter);
mWallpaperChangedReceiver.onReceive(mContext, null);
...
// 3. 利用从StatusBarManagerService获取到的信息,设置图标的初始状态
int N = iconSlots.size();
for (int i=0; i < N; i++) {
mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
}
// 4. 设置系统启动完毕需要显示的图标
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
...
//还监听了 BANNER_ACTION_CANCEL 和 BANNER_ACTION_SETUP
IntentFilter internalFilter = new IntentFilter();
internalFilter.addAction(BANNER_ACTION_CANCEL);
internalFilter.addAction(BANNER_ACTION_SETUP);
mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
null);
IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
Context.VR_SERVICE));
...
}
private static final String BANNER_ACTION_CANCEL = "com.android.systemui.statusbar.banner_action_cancel";
private static final String BANNER_ACTION_SETUP = "com.android.systemui.statusbar.banner_action_setup";
看下上面所说的createAndAddWindows方法:
public void createAndAddWindows() {
addStatusBarWindow();
}
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
...
}
// 初始化view
protected void makeStatusBarView() {
final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
inflateStatusBarWindow(context);
mStatusBarWindow.setService(this);
mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
mZenController.addCallback(this);
mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow, this, mNotificationPanel, mStackScroller);
}
...
mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
R.id.notification_container_parent));
mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
...
FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
mStatusBarView = (PhoneStatusBarView) fragment.getView();
mStatusBarView.setBar(this);
mStatusBarView.setPanel(mNotificationPanel);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setBouncerShowing(mBouncerShowing);
if (mHeadsUpAppearanceController != null) {
// This view is being recreated, let's destroy the old one
mHeadsUpAppearanceController.destroy();
}
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
setAreThereNotifications();
checkBarModes();
}).getFragmentManager()
.beginTransaction()
//把status_bar_container启动了一个CollapsedStatusBarFragment。
.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
CollapsedStatusBarFragment.TAG)
.commit();
...
mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
...
方法如下:
void updateDisplaySize() {
mDisplay.getMetrics(mDisplayMetrics);
mDisplay.getSize(mCurrentDisplaySize);
if (DEBUG_GESTURES) {
mGestureRec.tag("display",
String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
}
}
/**
配置更改时重新加载一些资源。在配置更改时,我们不会重新加载所有内容——我们可能应该这样做,但要获得平滑是很困难的总有一天我们会解决的。同时,更新我们知道的变化
*/
void updateResources() {
// Update the quick setting tiles
if (mQSPanel != null) {
mQSPanel.updateResources();
}
loadDimens();
if (mStatusBarView != null) {
mStatusBarView.updateResources();
}
if (mNotificationPanel != null) {
mNotificationPanel.updateResources();
}
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.updateResources();
}
}
//重要的总是在最后面
protected void inflateStatusBarWindow(Context context) {
mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
R.layout.super_status_bar, null);
}
下面图片引用自 文章
好吧,简单陈述一下:
StatusBar.java
-> start
-> createAndAddWindows
-> addStatusBarWindow
-> makeStatusBarView
-> inflateStatusBarWindow
上面代码中可以看到 把status_bar_container启动了一个CollapsedStatusBarFragment,
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.status_bar, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mStatusBar = (PhoneStatusBarView) view;
//icons
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
//mSystemIconArea用来显示状态栏左边图标的区域
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
//carrierText用来显示网络供应商的名称
carrierText = (CarrierText)mStatusBar.findViewById(R.id.system_carrier_text);
//mSignalClusterView则是用来显示信号相关的信息
mSignalClusterView = mStatusBar.findViewById(R.id.signal_cluster);
// Default to showing until we know otherwise.
showSystemIconArea(false);
initEmergencyCryptkeeperText();
}
1 对应的是notification_icon_area,平日里显示的都是notifications,如三方和系统的一些通知。
2 对应的是statusIcons,平日里显示的一些系统状态,如蓝牙、闹铃等。
3 是信号集群,显示的是信号相关的view,如wifi,cell信号格等,对应的是signal_cluster_view.xml。
4 则是剩余的两个独立的图标, 分别为电池电量显示、时间显示。
更多细节,请看下篇
status_bar.xml 去掉部分不重要的代码:
<com.android.systemui.statusbar.phone.PhoneStatusBarView
android:id="@+id/status_bar"
android:background="@drawable/system_bar_background"
android:focusable="false"
android:descendantFocusability="afterDescendants"
android:accessibilityPaneTitle="@string/status_bar"
>
<ImageView
android:id="@+id/notification_lights_out"
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:visibility="gone"
/>
<LinearLayout android:id="@+id/status_bar_contents"
android:orientation="horizontal"
>
<ViewStub
android:id="@+id/operator_name"
android:layout="@layout/operator_name" />
<FrameLayout
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1">
<include layout="@layout/heads_up_status_bar_layout" />
<LinearLayout
android:id="@+id/status_bar_left_side"
android:clipChildren="false"
>
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:singleLine="true"
android:gravity="center_vertical|start"
/>
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
android:clipChildren="false"/>
LinearLayout>
FrameLayout>
<android.widget.Space
android:id="@+id/cutout_space_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
/>
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/system_icon_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center_vertical|end"
>
<include layout="@layout/system_icons" />
com.android.keyguard.AlphaOptimizedLinearLayout>
LinearLayout>
<ViewStub
android:id="@+id/emergency_cryptkeeper_text"
android:layout="@layout/emergency_cryptkeeper_text"
/>
com.android.systemui.statusbar.phone.PhoneStatusBarView>
system_icons:信号区域:signal_cluster_view、状态栏电池,statusIcons(蓝牙、飞行模式statusIcons)。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/system_icons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding"
android:gravity="center_vertical"
android:orientation="horizontal"
android:tag="@string/status_bar_tag"/>
<com.android.systemui.BatteryMeterView android:id="@+id/battery"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:tag="statusbar" />
LinearLayout>