Android P SystemUI之StatusBar Wifi图标更新逻辑

本文详细解析了Android系统中状态栏WiFi图标从网络状态变化到图标显示的完整流程,涉及NetworkController、WifiSignalController、StatusBarSignalPolicy等多个组件的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相关源码:
\frameworks\base\packages\SystemUI\src\com\android\systemui\Dependency.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\StatusBarSignalPolicy.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\CollapsedStatusBarFragment.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\StatusBarIconController.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\StatusBarIconControllerImpl.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\NetworkController.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\WifiSignalController.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\SignalController.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\NetworkControllerImpl.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\WifiIcons.java

在文章中《Android P SystemUI之StatusBar UI布局status_bar.xml解析》讲到,wifi,蓝牙等系统图标的UI是在system_icons.xml中。

system_icons.xml

<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"
    android:orientation="horizontal">
    <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.BatteryMeterView 
        android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:clipToPadding="false"
        android:clipChildren="false" />
</LinearLayout>

关键点:android:id="@+id/statusIcons",我需要查看是哪里加载了statusIcons。

CollapsedStatusBarFragment.java

private DarkIconManager mDarkIconManager;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mStatusBar = (PhoneStatusBarView) view;
    if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
        mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
    }
    mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
    mDarkIconManager.setShouldLog(true);
    Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
    mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
    mClockView = mStatusBar.findViewById(R.id.clock);
    showSystemIconArea(false);
    showClock(false);
    initEmergencyCryptkeeperText();
    initOperatorName();
}

关键点1: mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
关键点2:Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);

这里创建了一个DarkIconManager,添加了statusIcons的view,并且添加到StatusBarIconController中。

StatusBarIconController.java

StatusBarIconController是一个接口,并且包含一个DarkIconManager的内部类,

Dependency.java

Dependency也是在SystemBars中启动的,执行如下:

@Override
public void start() {
	//省略一部分代码
	//...
    mProviders.put(StatusBarIconController.class, () ->
            new StatusBarIconControllerImpl(mContext));
	//省略一部分代码
	//...
}

我们只关心StatusBarIconController这一块,实现的是StatusBarIconControllerImpl。

StatusBarIconControllerImpl.java

private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
@Override
public void addIconGroup(IconManager group) {
    mIconGroups.add(group);
    List<Slot> allSlots = getSlots();
    for (int i = 0; i < allSlots.size(); i++) {
        Slot slot = allSlots.get(i);
        List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
        boolean blocked = mIconBlacklist.contains(slot.getName());

        for (StatusBarIconHolder holder : holders) {
            int tag = holder.getTag();
            int viewIndex = getViewIndex(getSlotIndex(slot.getName()), holder.getTag());
            group.onIconAdded(viewIndex, slot.getName(), blocked, holder);
        }
    }
}

/**
 * Signal icons need to be handled differently, because they can be
 * composite views
 */
@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);
    }
}

@Override
public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
    boolean isNew = getIcon(index, holder.getTag()) == null;
    super.setIcon(index, holder);

    if (isNew) {
        addSystemIcon(index, holder);
    } else {
        handleSet(index, holder);
    }
}

private void addSystemIcon(int index, StatusBarIconHolder holder) {
    String slot = getSlotName(index);
    int viewIndex = getViewIndex(index, holder.getTag());
    boolean blocked = mIconBlacklist.contains(slot);

    mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
    mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
}

通过setSignalIcon设置系统图标,包括Wifi,蓝牙等。

StatusBarSignalPolicy.java

    @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);
   }
}

setWifiIndicators()收到wifi状态变化后执行,调用updateWifiIconWithState()更新图标。

注册Wifi监听回调的地方:

public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
    mContext = context;

    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);
    mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);

    mIconController = iconController;
    mNetworkController = Dependency.get(NetworkController.class);
    mSecurityController = Dependency.get(SecurityController.class);

	//注册wifi状态回调
    mNetworkController.addCallback(this);
    mSecurityController.addCallback(this);
}

NetworkController,java

NetworkController包含了接口SignalCallback

WifiSignalController.java

@Override
public void notifyListeners(SignalCallback callback) {
    // only show wifi in the cluster if connected or if wifi-only
    boolean wifiVisible = mCurrentState.enabled
            && (mCurrentState.connected || !mHasMobileData);
    String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
    boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
    String contentDescription = getStringIfExists(getContentDescription());
    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, getQsCurrentIconId(),
            contentDescription);
    callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
            ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
            wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
}

回调执行了setWifiIndicators,去更新wifi状态。

NetworkControllerImpl.java

NetworkControllerImpl实现了接口NetworkController,并且保存了StatusBarSignalPolicy的回调对象,监听了wifi状态变化。

NetworkControllerImpl继承了BroadcastReceiver,在onReceive中接收广播。

onReceive()监听了各种状态的变化。

@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:
            updateConnectivity();
            break;
        case Intent.ACTION_AIRPLANE_MODE_CHANGED:
            refreshLocale();
            updateAirplaneMode(false);
            break;
        case TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
            // We are using different subs now, we might be able to make calls.
            recalculateEmergency();
            break;
        case TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
            // Notify every MobileSignalController so they can know whether they are the
            // data sim or not.
            for (int i = 0; i < mMobileSignalControllers.size(); i++) {
                MobileSignalController controller = mMobileSignalControllers.valueAt(i);
                controller.handleBroadcast(intent);
            }
            break;
        case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
            // Avoid rebroadcast because SysUI is direct boot aware.
            if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                break;
            }
            // Might have different subscriptions now.
            updateMobileControllers();
            break;
        case TelephonyIntents.ACTION_SERVICE_STATE_CHANGED:
            mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
            if (mMobileSignalControllers.size() == 0) {
                // If none of the subscriptions are active, we might need to recalculate
                // emergency state.
                recalculateEmergency();
            }
            break;
        case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
            mConfig = Config.readConfig(mContext);
            mReceiverHandler.post(this::handleConfigurationChanged);
            break;
        default:
            int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
            if (SubscriptionManager.isValidSubscriptionId(subId)) {
                if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
                    mMobileSignalControllers.get(subId).handleBroadcast(intent);
                } else {
                    // Can't find this subscription...  We must be out of date.
                    updateMobileControllers();
                }
            } else {
                // No sub id, must be for the wifi.
                mWifiSignalController.handleBroadcast(intent);
            }
            break;
    }
}

关注点: mWifiSignalController.handleBroadcast(intent);

WifiIcons.java

Wifi图标显示在WifiIcons定义如下:

public class WifiIcons {
    static final int[][] WIFI_SIGNAL_STRENGTH = {
            { R.drawable.stat_sys_wifi_signal_0,
              R.drawable.stat_sys_wifi_signal_1,
              R.drawable.stat_sys_wifi_signal_2,
              R.drawable.stat_sys_wifi_signal_3,
              R.drawable.stat_sys_wifi_signal_4 },
            { R.drawable.stat_sys_wifi_signal_0_fully,
              R.drawable.stat_sys_wifi_signal_1_fully,
              R.drawable.stat_sys_wifi_signal_2_fully,
              R.drawable.stat_sys_wifi_signal_3_fully,
              R.drawable.stat_sys_wifi_signal_4_fully }
        };

    public static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
            { R.drawable.ic_qs_wifi_0,
              R.drawable.ic_qs_wifi_1,
              R.drawable.ic_qs_wifi_2,
              R.drawable.ic_qs_wifi_3,
              R.drawable.ic_qs_wifi_4 },
            { R.drawable.ic_qs_wifi_full_0,
              R.drawable.ic_qs_wifi_full_1,
              R.drawable.ic_qs_wifi_full_2,
              R.drawable.ic_qs_wifi_full_3,
              R.drawable.ic_qs_wifi_full_4 }
        };

    static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network;
    static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null;

    static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length;
}

整理一下wifi信号发生的整个流程:

NetworkControllerImpl–>WifiSignalController–>SignalController–>WifiSignalController–>StatusBarSignalPolicy–>StatusBarIconController–>StatusBarIconControllerImpl–>CollapsedStatusBarFragment–>system_icons.xml

其中WifiSignalController

<think>好的,我现在需要帮用户解决在Android 14.0SystemUI中隐藏状态栏的WiFi流量上下行图标的问题。首先,我得回忆一下Android SystemUI的相关结构和代码位置。通常,状态栏的图标管理在StatusBarIconController或其相关的策略类中处理。 用户提到的WiFi流量上下行图标,应该是指当有数据传输时显示的上下箭头图标。这些图标通常由StatusBarSignalPolicy或类似的策略类控制。根据引用中的代码片段,比如StatusBarSignalPolicy.java中的setEthernetIndicators方法,这里涉及到图标的可见性设置,通过mIconController.setIconVisibility来控制。所以,类似的逻辑可能适用于WiFi图标。 接下来,我需要找到管理WiFi信号图标的代码部分。可能是在StatusBarSignalPolicy中,或者WifiSignalController这样的类里。查看引用[1]中的例子,设置以太网图标可见性的逻辑是检查visible和resId,然后调用setIconVisibility。所以,如果用户想隐藏WiFi的上下行图标,可能需要修改对应的visible标志或直接设置其可见性为false。 另外,引用[2]中提到系统图标如时间和电池的可见性是通过布局文件中的android:visibility属性设置的。虽然流量图标可能不是在布局文件中定义,但可能需要检查是否有相关的布局或资源文件控制这些图标的显示。 可能的步骤包括: 1. 找到控制WiFi信号图标显示的相关类,比如WifiSignalController或MobileSignalController。 2. 在这些类中找到设置上下行图标的方法,可能是在updateIconState或类似的方法中。 3. 修改对应的visible标志,或者在调用setIconVisibility时直接设置为false。 4. 如果图标是单独的资源,可能需要注释掉相关的绘制代码或布局引用。 需要注意的是,不同的Android版本可能会有代码结构的调整,Android 14.0的代码可能与之前版本有所不同,所以需要确认具体的类和方法路径。此外,修改SystemUI后需要重新编译并部署模块,可能需要使用Android Studio或AOSP环境进行编译。 另外,用户可能需要了解如何禁用流量箭头的功能,而不仅仅是隐藏图标,所以需要确保修改的是正确的位置,避免影响其他功能。比如,某些设备可能在SystemUIstatusbar模块中有专门的设置来控制流量指示器的显示,或者通过资源文件配置。因此,检查资源文件中的相关bool值,比如config_showActivityIndicator,将其设置为false可能也是一种方法。 总结下来,步骤应该是定位到控制WiFi流量图标的代码部分,修改其可见性设置,并确保编译和测试修改后的SystemUI。</think>在 Android 14.0 SystemUI 中隐藏状态栏 WiFi 流量上下行图标,可通过以下步骤实现: ### 一、定位图标控制逻辑 1. **核心控制类** WiFi流量上下行图标由 `StatusBarSignalPolicy` 或 `WifiSignalController` 控制。参考 `StatusBarSignalPolicy.java` 中以太网图标的处理逻辑[^1],WiFi 流量图标可能通过类似 `mIconController.setIconVisibility` 的方法控制可见性。 2. **关键代码路径** 相关代码可能位于: ```text SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java ``` ### 二、修改图标可见性 1. **直接隐藏流量箭头** 在 `WifiSignalController.java` 的 `updateIconState` 方法中,找到流量上下行状态判断逻辑,强制设置 `activityIn` 和 `activityOut` 为 false: ```java // 修改前 iconState.activityIn = mCurrentState.activityIn; iconState.activityOut = mCurrentState.activityOut; // 修改后 iconState.activityIn = false; iconState.activityOut = false; ``` 2. **拦截图标渲染** 在 `StatusBarIconControllerImpl.java` 中拦截 WiFi 图标的上下行标识: ```java // 添加判断条件 if (slot.equals(mSlotWifi)) { icon.icon = icon.icon.withoutActivityTracker(); // 清除流量箭头 } ``` ### 三、资源文件调整(可选) 若图标通过 XML 布局定义,可在 `system_icons.xml` 或 `status_bar.xml` 中添加可见性控制[^2]: ```xml <!-- 示例:隐藏特定图标容器 --> <LinearLayout android:id="@+id/wifi_activity_container" android:visibility="gone" /> ``` ### 四、编译与验证 1. 使用 Android Studio 或 AOSP 环境编译修改后的 SystemUI 模块 2. 通过 `adb push` 部署到设备 3. 重启 SystemUI 或设备验证效果: ```bash adb shell am restart com.android.systemui ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaolin2016

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值