SystemUI中StatusBar的图标控制器实现类为StatusBarIconControllerImpl,其继承了StatusBarIconController的接口,用于跟踪所有图标的状态,并将对应的状态发送给注册的图标管理器(IconManagers)。当我们在StatusBar中获取到它的实例后,还会将它传给PhoneStatusBarPolicy和StatusBarSignalPolicy对象。PhoneStatusBarPolicy控制启动时装载哪些图标(蓝牙,定位等),而StatusBarSignalPolicy控制网络信号图标(移动网络,WiFi,以太网)的变化。 一起来看 StatuBar 的 start() 方法:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
1 2 3 4 5 6 7 8 9 10 11 12 @Override public void start () { createAndAddWindows(); mIconPolicy.init(); mSignalPolicy = new StatusBarSignalPolicy (mContext, mIconController); }
这里的 mIconPolicy 就是 PhoneStatusBarPolicy对象,mSignalPolicy 就是 StatusBarSignalPolicy 对象。我们这里以 StatusBarSignalPolicy 为例去研究。 StatusBarSignalPolicy实现了NetworkControllerImpl.SignalCallback接口,SignalCallback接口定义在NetworkControllerImpl实现的接口NetworkController中。frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 @Inject public NetworkControllerImpl (Context context, @Background Looper bgLooper, DeviceProvisionedController deviceProvisionedController, BroadcastDispatcher broadcastDispatcher, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, WifiManager wifiManager, NetworkScoreManager networkScoreManager) { this (context, connectivityManager, telephonyManager, wifiManager, networkScoreManager, SubscriptionManager.from(context), Config.readConfig(context), bgLooper, new CallbackHandler (), new AccessPointControllerImpl (context), new DataUsageController (context), new SubscriptionDefaults (), deviceProvisionedController, broadcastDispatcher); mReceiverHandler.post(mRegisterListeners); } private final Runnable mRegisterListeners = new Runnable () { @Override public void run () { registerListeners(); } }; void registerListeners () { for (int i = 0 ; i < mMobileSignalControllers.size(); i++) { MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); mobileSignalController.registerListener(); } if (mSubscriptionListener == null ) { mSubscriptionListener = new SubListener (); } mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); IntentFilter filter = new IntentFilter (); filter.addAction(WifiManager.RSSI_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); mContext.registerReceiver(this , filter, null , mReceiverHandler); mListening = true ; updateMobileControllers(); }
在NetworkControllerImpl 的构造方法里,最终会调用到:registerListeners() 方法进行广播的注册。 广播处理:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 @Override public void onReceive (Context context, Intent intent) { if (CHATTY) { Log.d(TAG, "onReceive: intent=" + intent); } final String action = intent.getAction(); switch (action) { case ConnectivityManager.CONNECTIVITY_ACTION: case ConnectivityManager.INET_CONDITION_ACTION: break ; case Intent.ACTION_AIRPLANE_MODE_CHANGED: break ; case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED: break ; case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: break ; case Intent.ACTION_SIM_STATE_CHANGED: break ; case Intent.ACTION_SERVICE_STATE: break ; case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: break ; case ImsManager.ACTION_IMS_SERVICE_UP: case ImsManager.ACTION_IMS_SERVICE_DOWN: break ; case ACTION_HIGH_DEF_AUDIO_SUPPORT: break ; case ACTION_MODEM_CHANGE: break ; default : int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (SubscriptionManager.isValidSubscriptionId(subId)) { if (mMobileSignalControllers.indexOfKey(subId) >= 0 ) { mMobileSignalControllers.get(subId).handleBroadcast(intent); } else { updateMobileControllers(); } } else { mWifiSignalController.handleBroadcast(intent); } break ; } }
这里以 wifi状态图标处理 为例;接下来看WifiSignalController#handleBroadcast():frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
1 2 3 4 5 6 7 8 9 10 public void handleBroadcast (Intent intent) { mWifiTracker.handleBroadcast(intent); mCurrentState.enabled = mWifiTracker.enabled; mCurrentState.connected = mWifiTracker.connected; mCurrentState.ssid = mWifiTracker.ssid; mCurrentState.rssi = mWifiTracker.rssi; mCurrentState.level = mWifiTracker.level; mCurrentState.statusLabel = mWifiTracker.statusLabel; notifyListenersIfNecessary(); }
在WifiSignalController#handleBroadcast()方法中,就两个实现,一个是获取 WiFi 的状态,一个是通知更新状态。 我们直接看通知SignalController# notifyListenersIfNecessary() :frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
1 2 3 4 5 6 7 8 9 10 public void notifyListenersIfNecessary () { if (isDirty()) { saveLastState(); notifyListeners(); } } public final void notifyListeners () { notifyListeners(mCallbackHandler); } public abstract void notifyListeners (SignalCallback callback) ;
notifyListener()方法的实现在WifiSignalController类中:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Override public void notifyListeners (SignalCallback callback) { boolean visibleWhenEnabled = mContext.getResources().getBoolean( R.bool.config_showWifiIndicatorWhenEnabled); boolean wifiVisible = mCurrentState.enabled && ( (mCurrentState.connected && mCurrentState.inetCondition == 1 ) || !mHasMobileDataFeature || mWifiTracker.isDefaultNetwork || visibleWhenEnabled); String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null ; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null ; String contentDescription = getTextIfExists(getContentDescription()).toString(); if (mCurrentState.inetCondition == 0 ) { contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet)); } IconState statusIcon = new IconState (wifiVisible, getCurrentIconId(), contentDescription); IconState qsIcon = new IconState (mCurrentState.connected, mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected : getQsCurrentIconId(), contentDescription); callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon, ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut, wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel); }
可以看到,这里回调了StatusBarSignalPolicy#setWifiIndicators() 方法:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public void setWifiIndicators (boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient, String statusLabel) { boolean visible = statusIcon.visible && !mBlockWifi; boolean in = activityIn && mActivityEnabled && visible; boolean out = activityOut && mActivityEnabled && visible; WifiIconState newState = mWifiIconState.copy(); newState.visible = visible; newState.resId = statusIcon.icon; newState.activityIn = in; newState.activityOut = out; newState.slot = mSlotWifi; newState.airplaneSpacerVisible = mIsAirplaneMode; newState.contentDescription = statusIcon.contentDescription; MobileIconState first = getFirstMobileState(); newState.signalSpacerVisible = first != null && first.typeId != 0 ; updateWifiIconWithState(newState); mWifiIconState = newState; } private void updateWifiIconWithState (WifiIconState state) { if (state.visible && state.resId > 0 ) { mIconController.setSignalIcon(mSlotWifi, state); mIconController.setIconVisibility(mSlotWifi, true ); } else { mIconController.setIconVisibility(mSlotWifi, false ); } }
通过StatusBarIconController接口设置图标的套路都是一样的:
获取图标名字
监听事件
通过StatusBarIconControllerImpl相应的方法设置图标。 接下来再看StatusBarIconControllerImpl#setSignalIcon():
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public void setSignalIcon (String slot, WifiIconState state) { int index = getSlotIndex(slot); if (state == null ) { removeIcon(index, 0 ); return ; } StatusBarIconHolder holder = getIcon(index, 0 ); if (holder == null ) { holder = StatusBarIconHolder.fromWifiIconState(state); setIcon(index, holder); } else { holder.setWifiState(state); handleSet(index, holder); } }
首先设置WiFi的状态信息,遍历mIconGroups分别执行StatusBarIconController接口中静态类IconManager中的onIconAdded()和onSetIconHolder()的回调。 IconManager用于将信息从StatusBarIconController转换为ViewGroup中的ImageViews(com.android.systemui.statusbar.AlphaOptimizedImageView)。 接着看IconManager中的onIconAdded()和onSetIconHolder()方法:这两个方法一个用于添加、一个用于更新。frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 public interface StatusBarIconController { .... public static class DarkIconManager extends IconManager { .... public DarkIconManager (LinearLayout linearLayout) { super (linearLayout); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); } .... @Override protected void onIconAdded (int index, String slot, boolean blocked, StatusBarIconHolder holder) { StatusIconDisplayable view = addHolder(index, slot, blocked, holder); .... } } public static class IconManager implements DemoMode { .... protected final ViewGroup mGroup; protected final Context mContext; public IconManager (ViewGroup group) { mGroup = group; mContext = group.getContext(); mIconSize = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_height); .... } .... protected StatusIconDisplayable addHolder (int index, String slot, boolean blocked, StatusBarIconHolder holder) { switch (holder.getType()) { case TYPE_ICON: return addIcon(index, slot, blocked, holder.getIcon()); case TYPE_WIFI: return addSignalIcon(index, slot, holder.getWifiState()); case TYPE_MOBILE: return addMobileIcon(index, slot, holder.getMobileState()); } return null ; } @VisibleForTesting protected StatusBarWifiView addSignalIcon (int index, String slot, WifiIconState state) { StatusBarWifiView view = onCreateStatusBarWifiView(slot); view.applyWifiState(state); mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { mDemoStatusIcons.addDemoWifiView(state); } return view; } private StatusBarWifiView onCreateStatusBarWifiView (String slot) { StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot); return view; } .... public void onSetIconHolder (int viewIndex, StatusBarIconHolder holder) { switch (holder.getType()) { case TYPE_ICON: onSetIcon(viewIndex, holder.getIcon()); return ; case TYPE_WIFI: onSetSignalIcon(viewIndex, holder.getWifiState()); return ; case TYPE_MOBILE: onSetMobileIcon(viewIndex, holder.getMobileState()); default : break ; } } public void onSetSignalIcon (int viewIndex, WifiIconState state) { StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex); if (wifiView != null ) { wifiView.applyWifiState(state); } if (mIsInDemoMode) { mDemoStatusIcons.updateWifiState(state); } } .... } }
这里根据不同的StatusBarIconHolder类型,设置不同的网络Icon,上面列出了 Wifi 图标相关的方法。 SystemUI状态栏图标根据源码可大体分为三种:
StatusBarIconView
StatusBarWifiView
StatusBarMobileView
这里主要以Wifi 相关图标(StatusBarWifiView)进行分析,添加Icon时首先会创建一个 StatusBarWifiView,然后调用StatusBarWifiView的applyWifiState更新其显示状态,最后将其加入到CollapsedStatusBarFragment中放置Icon的ViewGroup中,这样就完成了添加过程; 再来看看 CollapsedStatusBarFragment:SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue .Callbacks { .... private DarkIconManager mDarkIconManager; .... @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) { .... mDarkIconManager = new DarkIconManager (view.findViewById(R.id.statusIcons)); mDarkIconManager.setShouldLog(true ); Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager); .... } }
补充: notifyListenersIfNecessary()在其父类SignalController中定义,frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 private final CallbackHandler mCallbackHandler; public void notifyListenersIfNecessary () { if (isDirty()) { saveLastState(); notifyListeners(); } } public final void notifyListeners () { notifyListeners(mCallbackHandler); } public abstract void notifyListeners (SignalCallback callback) ;
CallbackHandler维护了所有需要监听的SignalCallback接口对象,我们的StatusBarSignalPolicy就实现了该接口。 StatusBarSignalPolicy主要执行网络图标的刷新动作,其实现了NetworkControllerImpl.SignalCallback接口,然后注册到NetworkController,其具体实现类NetworkControllerImpl会根据WIFI,SIM等状态广播来进一步派发给具体的Controller,例如WifiSignalController,每个Controller只与CallbackHandler交互,然后CallbackHandler继续转交给维护的SignalCallback接口的具体实现类,例如StatusBarSignalPolicy
本文链接: http://longzhiye.top/2023/11/26/2023-11-26/