这篇首要学习下非打开的状态栏,也便是缩短状态栏,下图红线部分
1.温习下StatusBarWindowView
温习下,上节5.3里面有讲,StatusBar加载的布局是R.layout.super_status_bar,下边再简略整理下相关的流程
首要CentralSurfacesImpl.java的结构办法里实例化了StatusBarWindowController.java,而StatusBarWindowController的结构办法里又实例化了StatusBarWindowView,完事attach办法addView
StatusBarWindowController
@Inject
public StatusBarWindowController(
Context context,
//结构办法传递的view
@StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
//...
public void attach() {
mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
// 增加view
mWindowManager.addView(mStatusBarWindowView, mLp);
CentralSurfacesImpl.java里面会调用StatusBarWindowController的attach办法
@Inject
public CentralSurfacesImpl(
//...
StatusBarWindowController statusBarWindowController,//controller
//...
public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
makeStatusBarView(result);
mNotificationShadeWindowController.attach();
mStatusBarWindowController.attach();//这行
}
getBarLayoutParams
如下,状态栏高度是固定的
private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
int height = SystemBarUtils.getStatusBarHeightForRotation(mContext, rotation);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
height,
StatusBarWindowView
注解生成的,如下
@Module
abstract class StatusBarWindowModule {
@Module
companion object {
@JvmStatic
@Provides
@SysUISingleton
@InternalWindowView
fun providesStatusBarWindowView(layoutInflater: LayoutInflater): StatusBarWindowView {
return layoutInflater.inflate(
R.layout.super_status_bar,
/* root= */null
) as StatusBarWindowView?
}
布局super_status_bar
<!-- This is the status bar window. -->
<com.android.systemui.statusbar.window.StatusBarWindowView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="@+id/status_bar_launch_animation_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/status_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/system_bar_background" />
</com.android.systemui.statusbar.window.StatusBarWindowView>
之后那个id为status_bar_container的布局会被替换成一个Fragment,详细逻辑在上节5.1的下边这行代码
## CentralSurfacesImpl.java
// Set up CollapsedStatusBarFragment and PhoneStatusBarView
StatusBarInitializer initializer = mCentralSurfacesComponent.getStatusBarInitializer();
//...
initializer.initializeStatusBar(mCentralSurfacesComponent);
StatusBarInitializer
StatusBarInitializer.kt经过replace办法,把布局里的容器换成了Fragment
fun initializeStatusBar(
centralSurfacesComponent: CentralSurfacesComponent
) {
windowController.fragmentHostManager.addTagListener(
CollapsedStatusBarFragment.TAG,
object : FragmentHostManager.FragmentListener {
override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
val statusBarFragmentComponent = (fragment as CollapsedStatusBarFragment)
.statusBarFragmentComponent ?: throw IllegalStateException()
statusBarViewUpdatedListener?.onStatusBarViewUpdated(
statusBarFragmentComponent.phoneStatusBarView,//注解获取的
statusBarFragmentComponent.phoneStatusBarViewController,
statusBarFragmentComponent.phoneStatusBarTransitions
)
creationListeners.forEach { listener ->
listener.onStatusBarViewInitialized(statusBarFragmentComponent)
}
}
override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
// nop
}
}).fragmentManager
.beginTransaction()
.replace(R.id.status_bar_container,//这儿
centralSurfacesComponent.createCollapsedStatusBarFragment(),//替换的fragment
CollapsedStatusBarFragment.TAG)
.commit()
}
centralSurfacesComponent.createCollapsedStatusBarFragment() 这个注解生成的fragment便是下边要讲的
2.CollapsedStatusBarFragment
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
status_bar.xml
先看下这个fragment加载的布局。
<?xml version="1.0" encoding="utf-8"?>
## 帧布局
<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:layout_width="match_parent"
android:layout_height="@dimen/status_bar_height"
android:id="@+id/status_bar"
android:orientation="vertical"
android:focusable="false"
android:descendantFocusability="afterDescendants"
android:accessibilityPaneTitle="@string/status_bar"
>
<ImageView
android:id="@+id/notification_lights_out"
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="match_parent"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingBottom="2dip"
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:visibility="gone"
/>
<LinearLayout android:id="@+id/status_bar_contents"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end"
android:paddingTop="@dimen/status_bar_padding_top"
android:orientation="horizontal">
<!-- Container for the entire start half of the status bar. It will always use the same
width, independent of the number of visible children and sub-children. -->
<FrameLayout
android:id="@+id/status_bar_start_side_container"
android:layout_height="match_parent"
android:layout_width="0dp"
android:clipChildren="false"
android:layout_weight="1">
<!-- Container that is wrapped around the views on the start half of the status bar.
Its width will change with the number of visible children and sub-children.
It is useful when we want to know the visible bounds of the content. -->
<FrameLayout
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false">
<include layout="@layout/heads_up_status_bar_layout" />
<!-- The alpha of the start side is controlled by PhoneStatusBarTransitions, and the
individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK
and DISABLE_NOTIFICATION_ICONS, respectively -->
<LinearLayout
android:id="@+id/status_bar_start_side_except_heads_up"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:clipChildren="false">
<ViewStub
android:id="@+id/operator_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout="@layout/operator_name" />
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:singleLine="true"
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
android:gravity="center_vertical|start"
/>
<include layout="@layout/ongoing_call_chip" />
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:clipChildren="false"/>
</LinearLayout>
</FrameLayout>
</FrameLayout>
<!-- Space should cover the notch (if it exists) and let other views lay out around it -->
<android.widget.Space
android:id="@+id/cutout_space_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
/>
<!-- Container for the entire end half of the status bar. It will always use the same
width, independent of the number of visible children and sub-children. -->
<FrameLayout
android:id="@+id/status_bar_end_side_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clipChildren="false">
<!-- Container that is wrapped around the views on the end half of the
status bar. Its width will change with the number of visible children and
sub-children.
It is useful when we want know the visible bounds of the content.-->
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/status_bar_end_side_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="horizontal"
android:gravity="center_vertical|end"
android:clipChildren="false">
<include
android:id="@+id/user_switcher_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
layout="@layout/status_bar_user_chip_container" />
<include layout="@layout/system_icons" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</FrameLayout>
</LinearLayout>
<ViewStub
android:id="@+id/emergency_cryptkeeper_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout="@layout/emergency_cryptkeeper_text"
/>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
其他相关的布局 ongoing_call_chip.xml
<!-- Have the wrapper frame layout match the parent height so that we get a larger touch area for
the chip. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ongoing_call_chip"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="5dp"
>
<LinearLayout
android:id="@+id/ongoing_call_chip_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/ongoing_appops_chip_height"
android:layout_gravity="center_vertical"
android:gravity="center"
android:background="@drawable/ongoing_call_chip_bg"
android:paddingStart="@dimen/ongoing_call_chip_side_padding"
android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
android:contentDescription="@string/ongoing_phone_call_content_description"
android:minWidth="@dimen/min_clickable_item_size"
>
<ImageView
android:src="@*android:drawable/ic_phone"
android:layout_width="@dimen/ongoing_call_chip_icon_size"
android:layout_height="@dimen/ongoing_call_chip_icon_size"
android:tint="?android:attr/colorPrimary"
/>
<com.android.systemui.statusbar.phone.ongoingcall.OngoingCallChronometer
android:id="@+id/ongoing_call_chip_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center|start"
android:paddingStart="@dimen/ongoing_call_chip_icon_text_padding"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:textColor="?android:attr/colorPrimary"
/>
</LinearLayout>
</FrameLayout>
1.PhoneStatusBarView
这个类首要计算下status bar的高度,监听下clock,batter图标的漆黑颜色变化,还有cutout_space_view的大小动态设置
public class PhoneStatusBarView extends FrameLayout {
简化下status_bar.xml布局如下,首要看下核心的第二层,里面有2个帧布局,比重是都是1
<com.android.systemui.statusbar.phone.PhoneStatusBarView
>
## 第一层
<ImageView
android:id="@+id/notification_lights_out"
/>
## 第二层
<LinearLayout android:id="@+id/status_bar_contents"
<FrameLayout
android:id="@+id/status_bar_start_side_container"
<android.widget.Space
android:id="@+id/cutout_space_view"
/>
<FrameLayout
android:id="@+id/status_bar_end_side_container"
</FrameLayout>
</LinearLayout>
## 第三层
<ViewStub
android:layout="@layout/emergency_cryptkeeper_text"
/>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
下边就详细来看下第二层布局里,左右两部分ui都有啥
>status_bar_start_side_container
状态栏左边部分
<LinearLayout android:id="@+id/status_bar_start_side_except_heads_up" >
# 像是sim卡运营商的姓名,调用的getCarrierName办法,fragment里初始化的
<ViewStub android:id="@+id/operator_name"
android:layout="@layout/operator_name" />
# 当前时刻
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock" />
# 通话时长
<include layout="@layout/ongoing_call_chip" />
# 其他告诉icon
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"/>
</LinearLayout>
>status_bar_end_side_container
状态栏右侧部分
<FrameLayout
android:id="@+id/status_bar_end_side_container">
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/status_bar_end_side_content">
# 当前用户的信息,头像和姓名
<include
android:id="@+id/user_switcher_container"
layout="@layout/status_bar_user_chip_container" />
#系统icons
<include layout="@layout/system_icons" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</FrameLayout>
布局system_icons.xml 能够看到,右侧固定有个电池图标
<LinearLayout
android:layout_gravity="center_vertical|end"
android:gravity="center_vertical">
## 这儿是动态增加的icon
<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"/>
## 固定有个电池控件
<com.android.systemui.battery.BatteryMeterView android:id="@+id/battery" />
</LinearLayout>
2.onViewCreated
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mStatusBarFragmentComponent.init();
//...
mStatusBar = (PhoneStatusBarView) view;
//...
//statusIcons便是右侧的icon容器,电量图标左边的部分
mDarkIconManager = mDarkIconManagerFactory.create(
view.findViewById(R.id.statusIcons), StatusBarLocation.HOME);
//...
updateBlockedIcons();//便是默许不显现的icon,从装备里读取,然后赋值给IconManager,显现的时分会判别过滤掉
mStatusBarIconController.addIconGroup(mDarkIconManager);//详细逻辑见下边概况
//...
initNotificationIconArea();//状态栏左边时刻控件右边的icons容器
//...
}
>DarkIconManager
继承IconManager,首要处理icon的动态增加逻辑,create办法第一个参数,便是icon要增加到的viewGroup
public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
return new DarkIconManager(
group,
location,
public DarkIconManager(
LinearLayout linearLayout,
StatusBarLocation location,
//...
DarkIconDispatcher darkIconDispatcher) {
super(linearLayout,
location,
IconManager,能够看到blocked字段对wifi和mobile图标是不收效的。
public IconManager(
ViewGroup group,
StatusBarLocation location,
//...
) {
mGroup = group;
mStatusBarPipelineFlags = statusBarPipelineFlags;
public void setBlockList(@Nullable List<String> blockList) {
mBlockList.clear();
mBlockList.addAll(blockList);
if (mController != null) {
mController.refreshIconGroup(this);
}
}
protected void onIconAdded(int index, String slot, boolean blocked,
StatusBarIconHolder holder) {
addHolder(index, slot, blocked, holder);
}
protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
StatusBarIconHolder holder) {
// This is a little hacky, and probably regrettable, but just set `blocked` on any icon
// that is in our blocked list, then we'll never see it
if (mBlockList.contains(slot)) {
blocked = true;
}
//下边add办法便是把view增加到mGroup里
switch (holder.getType()) {
case TYPE_ICON:
return addIcon(index, slot, blocked, holder.getIcon());
case TYPE_WIFI:
return addWifiIcon(index, slot, holder.getWifiState());
case TYPE_WIFI_NEW:
return addNewWifiIcon(index, slot);
case TYPE_MOBILE:
return addMobileIcon(index, slot, holder.getMobileState());
case TYPE_MOBILE_NEW:
return addNewMobileIcon(index, slot, holder.getTag());
}
return null;
}
>config_collapsed_statusbar_icon_blocklist
<!-- Icons that don't show in a collapsed non-keyguard statusbar -->
<string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
<item>@*android:string/status_bar_volume</item>
<item>@*android:string/status_bar_alarm_clock</item>
<item>@*android:string/status_bar_call_strength</item>
</string-array>
>addIconGroup办法
办法的完成是在这个类里frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
public void addIconGroup(IconManager group) {
//...
group.setController(this);
mIconGroups.add(group);
List<Slot> allSlots = mStatusBarIconList.getSlots();
for (int i = 0; i < allSlots.size(); i++) {
Slot slot = allSlots.get(i);
List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
boolean hidden = mIconHideList.contains(slot.getName());
//这儿刚开始holders调集是空的,所以啥也没干
for (StatusBarIconHolder holder : holders) {
int viewIndex = mStatusBarIconList.getViewIndex(slot.getName(), holder.getTag());
group.onIconAdded(viewIndex, slot.getName(), hidden, holder);
}
}
}
>>StatusBarIconList
这个目标是注解生成的,数据是装备里读取的,相关的数组在frameworks/base/core/res/res/values/config.xml 数组长度有30多个,就不贴了。
@Provides
@SysUISingleton
static StatusBarIconList provideStatusBarIconList(Context context) {
return new StatusBarIconList(
context.getResources().getStringArray(
com.android.internal.R.array.config_statusBarIcons));
}
public class StatusBarIconList {
private final ArrayList<Slot> mSlots = new ArrayList<>();
private final List<Slot> mViewOnlySlots = Collections.unmodifiableList(mSlots);
public StatusBarIconList(String[] slots) {
final int N = slots.length;
for (int i = 0; i < N; i++) {
mSlots.add(new Slot(slots[i], null));//就个姓名
}
}
/** Returns the list of current slots. */
public List<Slot> getSlots() {
return mViewOnlySlots;
}
能够看到,默许的Slot就姓名不是空的,其他都是空的,所以下边if条件都不满足。
public List<StatusBarIconHolder> getHolderListInViewOrder() {
ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
if (mSubSlots != null) {
for (int i = mSubSlots.size() - 1; i >= 0; i--) {
holders.add(mSubSlots.get(i));
}
}
if (mHolder != null) {
holders.add(mHolder);
}
return holders;
}
Fragment里代码看完了,没有发现增加icon的当地
3.onIconAdded
protected void onIconAdded(int index, String slot, boolean blocked,
StatusBarIconHolder holder) {
addHolder(index, slot, blocked, holder);
}
找不到icon哪里增加的,那从最基本的来找,便是前边的贴的IconManager里有addView的办法,所以查看哪里调用即可。我们Fragment里用到的是DarkIconManager,查下里面的onIconAdded办法都哪里用到,很简单找到StatusBarIconControllerImpl.java里有用到,这个类里有许多setIcon的办法,找些哪里用的, 最后发现icon都在下边2个XXXPolicy类里增加的。
4.PhoneStatusBarPolicy(一般图标)
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
>初始化
这个类是CentralSurfacesImpl的结构办法里生成的,然后在其start办法里init的,如下
//上一篇说过的,这个start会主动履行的
public void start() {
//...
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy.init();
CentralSurfacesImpl是完成接口CoreStartable的,会主动履行start办法
public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
>init办法
持续看这个类的init办法,能够看到里面增加的icon都默许不可见的,这儿应该便是初始化下icon数据,办法最后是一些监听回调,会动态修正图标的可见性。
// TTY status: teletypewriter,电传打字机的缩写,指的是一种用于文本通讯的设备
updateTTY();
// bluetooth status ,看了下逻辑,只有在蓝牙衔接而且audio正常的情况下才有这个图标
updateBluetooth();
// Alarm clock
mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
mIconController.setIconVisibility(mSlotAlarmClock, false);
// zen
mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
mIconController.setIconVisibility(mSlotZen, false);
// vibrate
mIconController.setIcon(mSlotVibrate, R.drawable.stat_sys_ringer_vibrate,
mResources.getString(R.string.accessibility_ringer_vibrate));
mIconController.setIconVisibility(mSlotVibrate, false);
// mute
mIconController.setIcon(mSlotMute, R.drawable.stat_sys_ringer_silent,
mResources.getString(R.string.accessibility_ringer_silent));
mIconController.setIconVisibility(mSlotMute, false);
updateVolumeZen();
// cast
mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
mIconController.setIconVisibility(mSlotCast, false);
// hotspot
mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
mResources.getString(R.string.accessibility_status_bar_hotspot));
mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
// managed profile
updateManagedProfile();
// data saver
mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
mResources.getString(R.string.accessibility_data_saver_on));
mIconController.setIconVisibility(mSlotDataSaver, false);
// privacy items
String microphoneString = mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId());
String microphoneDesc = mResources.getString(
R.string.ongoing_privacy_chip_content_multiple_apps, microphoneString);
mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(),
microphoneDesc);
mIconController.setIconVisibility(mSlotMicrophone, false);
String cameraString = mResources.getString(PrivacyType.TYPE_CAMERA.getNameId());
String cameraDesc = mResources.getString(
R.string.ongoing_privacy_chip_content_multiple_apps, cameraString);
mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(),
cameraDesc);
mIconController.setIconVisibility(mSlotCamera, false);
mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
mResources.getString(R.string.accessibility_location_active));
mIconController.setIconVisibility(mSlotLocation, false);
// sensors off
mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off,
mResources.getString(R.string.accessibility_sensors_off_active));
mIconController.setIconVisibility(mSlotSensorsOff,
mSensorPrivacyController.isSensorPrivacyEnabled());
// screen record
mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null);
mIconController.setIconVisibility(mSlotScreenRecord, false);
//下边这些回调,会动态修正图标的可见性
mRotationLockController.addCallback(this);
mBluetooth.addCallback(this);
mProvisionedController.addCallback(this);
mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
mZenController.addCallback(this);
mCast.addCallback(mCastCallback);
mHotspot.addCallback(mHotspotCallback);
mNextAlarmController.addCallback(mNextAlarmCallback);
mDataSaver.addCallback(this);
mKeyguardStateController.addCallback(this);
mPrivacyItemController.addCallback(this);
mSensorPrivacyController.addCallback(mSensorPrivacyListener);
mLocationController.addCallback(this);
mRecordingController.addCallback(this);
mCommandQueue.addCallback(this);
}
5 StatusBarSignalPolicy(信号图标)
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
>初始化
同上,也是CentralSurfacesImpl.java结构办法里实例化目标,start办法里履行init办法
public void start() {
//...
mStatusBarSignalPolicy.init();
>init办法
在监听里处理icon的
public void init() {
if (mInitialized) {
return;
}
mInitialized = true;
mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
}
看下这个类用到的字符串,就知道他都处理哪些图标了
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
mSlotVpn = mContext.getString(com.android.internal.R.string.status_bar_vpn);
mSlotNoCalling = mContext.getString(com.android.internal.R.string.status_bar_no_calling);
mSlotCallStrength =
mContext.getString(com.android.internal.R.string.status_bar_call_strength);
mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
6.setIcon
上边剖析过,StatusBarIconControllerImpl.java里有许多setIcon的办法,如下图
这儿就拿其间一种来剖析下流程,默许的holder是null的,所以下边的代码会进入if,创立新的holder
public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, 0);
if (holder == null) {
//实例化一个icon目标
StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
Icon.createWithResource(
mContext, resourceId), 0, 0, contentDescription);
//创立holder目标,并把icon赋值给holder目标
holder = StatusBarIconHolder.fromIcon(icon);
setIcon(slot, holder);
} else {
//更新下icon信息即可
holder.getIcon().icon = Icon.createWithResource(mContext, resourceId);
holder.getIcon().contentDescription = contentDescription;
handleSet(slot, holder);
}
}
>StatusBarIconHolder.fromIcon(icon)
public static StatusBarIconHolder fromIcon(StatusBarIcon icon) {
StatusBarIconHolder wrapper = new StatusBarIconHolder();
wrapper.mIcon = icon;
return wrapper;
}
>setIcon
前边剖析过mStatusBarIconList时注解生成的,默许里面的holder是null的,所以这儿判别下,为null就addIcon,不为null就做更新操作
private void setIcon(String slot, @NonNull StatusBarIconHolder holder) {
boolean isNew = mStatusBarIconList.getIconHolder(slot, holder.getTag()) == null;
mStatusBarIconList.setIcon(slot, holder);//给对应的icon设置holder
if (isNew) {
addSystemIcon(slot, holder);
} else {
handleSet(slot, holder);
}
}
持续
private void addSystemIcon(String slot, StatusBarIconHolder holder) {
int viewIndex = mStatusBarIconList.getViewIndex(slot, holder.getTag());
boolean hidden = mIconHideList.contains(slot);
//这个是增加新的icon view,mIconGroups里目前已知的是那个 mDarkIconManager
mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
}
>handleSet
private void handleSet(String slotName, StatusBarIconHolder holder) {
int viewIndex = mStatusBarIconList.getViewIndex(slotName, holder.getTag());
//这儿是找到就的icon view,更新其显现的图标
mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
}
7.Icon的品种
首要就一般的icon和特别的icon(wifi,mobile)
>一般的icon
protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
StatusBarIcon icon) {
StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
view.set(icon);
mGroup.addView(view, index, onCreateLayoutParams());
return view;
}
private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
return new StatusBarIconView(mContext, slot, null, blocked);
}
StatusBarIconView
public class StatusBarIconView extends AnimatedImageView implements StatusIconDisplayable {
view.set(icon)的办法,看下可见性的处理。能够看到,需求是icon自身可见而且block为false。
if (!visibilityEquals) {
setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
}
return true;
}
>特别的icon(wifi,mobile)
wifi ,new wifi ,mobile ,new mobile 是4种不同的view
final StatusBarWifiView view = onCreateStatusBarWifiView(slot);
ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
StatusBarMobileView mobileView = onCreateStatusBarMobileView(state.subId, slot);
BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);
>>新旧icon显现的判别
那么到底显现新的还是旧的,咋判别的?如下,能够看到是statusBarPipelineFlags这个类决议的
public IconManager(
ViewGroup group,
StatusBarLocation location,
StatusBarPipelineFlags statusBarPipelineFlags,
WifiUiAdapter wifiUiAdapter,
MobileUiAdapter mobileUiAdapter,
MobileContextProvider mobileContextProvider
) {
mGroup = group;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mMobileContextProvider = mobileContextProvider;
mContext = group.getContext();
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
mLocation = location;
//是否是新的mobile icon
if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
// This starts the flow for the new pipeline, and will notify us of changes if
// {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
} else {
mMobileIconsViewModel = null;
}
//是否是新的wifi icon
if (statusBarPipelineFlags.runNewWifiIconBackend()) {
// This starts the flow for the new pipeline, and will notify us of changes if
// {@link StatusBarPipelineFlags#useNewWifiIcon} is also true.
mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
} else {
mWifiViewModel = null;
}
}
持续,能够看到,又是由FeatureFlags决议,这个东西是个接口,有两种完成
class StatusBarPipelineFlags @Inject constructor(private val featureFlags: FeatureFlags) {
fun useNewMobileIcons(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS)
fun runNewMobileIconsBackend(): Boolean =
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS_BACKEND) || useNewMobileIcons()
fun useNewWifiIcon(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON)
fun runNewWifiIconBackend(): Boolean =
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON_BACKEND) || useNewWifiIcon()
如下,都是false
public class FeatureFlagsRelease implements FeatureFlags {
public boolean isEnabled(@NotNull UnreleasedFlag flag) {
return false;
}
debug模式下,能够看到直接用的便是参数flag的默许的值,详细的能够点进去用到的flag查看,默许都是false的
public class FeatureFlagsDebug implements FeatureFlags {
public boolean isEnabled(@NotNull UnreleasedFlag flag) {
return isEnabledInternal(flag);
}
private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
mBooleanFlagCache.put(id,
readBooleanFlagInternal(flag, flag.getDefault()));
}
return mBooleanFlagCache.get(id);
}
>>addMobileIcon
StatusBarMobileView mobileView = onCreateStatusBarMobileView(state.subId, slot);
StatusBarMobileView view = StatusBarMobileView
.fromContext(mobileContext, slot);
return view;
public static StatusBarMobileView fromContext(
Context context,
String slot
) {
LayoutInflater inflater = LayoutInflater.from(context);
StatusBarMobileView v = (StatusBarMobileView)
inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
v.setSlot(slot);
v.init();
v.setVisibleState(STATE_ICON);
return v;
}
布局看下
<com.android.systemui.statusbar.StatusBarMobileView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical" >
<include layout="@layout/status_bar_mobile_signal_group_inner" />
</com.android.systemui.statusbar.StatusBarMobileView>
status_bar_mobile_signal_group_inner.xml
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto" >
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/mobile_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal" >
//移动数据的接纳发送,图片是向上向下的箭头
<FrameLayout
android:id="@+id/inout_container"
android:layout_height="17dp"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/mobile_in"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
android:paddingEnd="2dp"
/>
<ImageView
android:id="@+id/mobile_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
android:paddingEnd="2dp"
android:visibility="gone"
/>
</FrameLayout>
//移动数据的类型
<ImageView
android:id="@+id/mobile_type"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="2.5dp"
android:paddingEnd="1dp"
android:visibility="gone" />
<Space
android:id="@+id/mobile_roaming_space"
android:layout_height="match_parent"
android:layout_width="@dimen/roaming_icon_start_padding"
android:visibility="gone"
/>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
systemui:hasOverlappingRendering="false"
/>
//小的漫游图标,左上角一个R
<ImageView
android:id="@+id/mobile_roaming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
</FrameLayout>
//大的漫游图标,居中的R
<ImageView
android:id="@+id/mobile_roaming_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stat_sys_roaming_large"
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</merge>
addWifiIcon
private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot);
return view;
}
public static StatusBarWifiView fromContext(Context context, String slot) {
LayoutInflater inflater = LayoutInflater.from(context);
StatusBarWifiView v = (StatusBarWifiView) inflater.inflate(R.layout.status_bar_wifi_group, null);
v.setSlot(slot);
v.init();
v.setVisibleState(STATE_ICON);
return v;
}
布局就不贴了,自己看下
8. exclude
便是决议哪些图标不显现,能够在装备里增加
>初始过滤
假如图标不想让它显现,把它增加在这儿就行了。
<string-array name="config_statusBarIconsToExclude" translatable="false">
<item>@*android:string/status_bar_rotate</item>
<item>@*android:string/status_bar_headset</item>
<item>@*android:string/status_bar_screen_record</item>
</string-array>
StatusBarIconControllerImpl.java
public void onTuningChanged(String key, String newValue) {
if (!ICON_HIDE_LIST.equals(key)) {
return;
}
mIconHideList.clear();
mIconHideList.addAll(StatusBarIconController.getIconHideList(mContext, newValue));
数据获取
static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
String[] hideList = hideListStr == null
? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
: hideListStr.split(",");
for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
ret.add(slot);
}
}
return ret;
}
这个调集的调用当地
private void addSystemIcon(String slot, StatusBarIconHolder holder) {
int viewIndex = mStatusBarIconList.getViewIndex(slot, holder.getTag());
boolean hidden = mIconHideList.contains(slot);
mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
}
>2次过滤
过滤的icon在这个数组里config_collapsed_statusbar_icon_blocklist,所以不想显现的图标也能够写在这个数组里。CollapsedStatusBarFragment.java
void updateBlockedIcons() {
mBlockedIcons.clear();
// Reload the blocklist from res
List<String> blockList = Arrays.asList(getResources().getStringArray(
R.array.config_collapsed_statusbar_icon_blocklist));
String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
boolean showVibrateIcon =//
// Filter out vibrate icon from the blocklist if the setting is on
mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
}
IconManager
public void setBlockList(@Nullable List<String> blockList) {
Assert.isMainThread();
mBlockList.clear();
mBlockList.addAll(blockList);
if (mController != null) {
mController.refreshIconGroup(this);
}
}
需求注意:wifi和mobile是不受这个block影响的。
protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
StatusBarIconHolder holder) {
//2次判别
if (mBlockList.contains(slot)) {
blocked = true;
}
switch (holder.getType()) {
case TYPE_ICON:
return addIcon(index, slot, blocked, holder.getIcon());
case TYPE_WIFI:
return addWifiIcon(index, slot, holder.getWifiState());
case TYPE_MOBILE:
return addMobileIcon(index, slot, holder.getMobileState());
}
}
3.总结
这篇首要介绍了状态栏(非打开状态)的图标显现逻辑。
- StatusBarView的增加
- 经过CollapsedStatusBarFragment管理icon的显现
- icon的管理类有2个,PhoneStatusBarPollicy以及StatusBarSignalPolicy
- 能够在string里装备哪些icon不用显现