Android 状态栏WiFi图标的显示逻辑

简介: Android 状态栏WiFi图标的显示逻辑

1. 状态栏信号图标

1.1 WIFI信号显示

WIFI信号在状态栏的显示如下图所示

当WiFi状态为关闭时,状态栏不会有任何显示。当WiFi状态打开时,会如上图所示,左侧表示有可用WiFi,右侧表示当前WiFi打开但未连接。

当WiFi状态连接时,会如上图所示,显示信号连接强度和数据连接状态。


1.2 图标更新流程框架


如图所示,WiFi图标的显示流程主要是通过监听系统的WiFi状态,然后通知UI去实时的刷新图标资源。NetworkControllerImpl.java 继承 BroadcastReceiver 监听系统WiFi状态的变化。


2. WIFI图标更新流介绍


2.1 重要类

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\connectivity\NetworkControllerImpl.java

定义相关函数,继承BroadcastReceiver监听系统广播,动态注册广播接收器。是状态栏WiFi图标更新的核心类。

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\connectivity\WifiIcons.java

定义了 Wifi 信号更新所需的图标资源。

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\connectivity\WifiSignalController.java


2.2 WIFI图标更新流程


(1)WifiNetworkController实例化,在NetworkControllerImpl.java进行实例化


frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\connectivity\NetworkControllerImpl.java

    @VisibleForTesting
    NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
            TelephonyManager telephonyManager,
            TelephonyListenerManager telephonyListenerManager,
            WifiManager wifiManager,
            SubscriptionManager subManager,
            Config config,
            Looper bgLooper,
            Executor bgExecutor,
            CallbackHandler callbackHandler,
            AccessPointControllerImpl accessPointController,
            StatusBarPipelineFlags statusBarPipelineFlags,
            DataUsageController dataUsageController,
            SubscriptionDefaults defaultsHandler,
            DeviceProvisionedController deviceProvisionedController,
            BroadcastDispatcher broadcastDispatcher,
            UserTracker userTracker,
            DemoModeController demoModeController,
            CarrierConfigTracker carrierConfigTracker,
            WifiStatusTrackerFactory trackerFactory,
            MobileSignalControllerFactory mobileFactory,
            @Main Handler handler,
            DumpManager dumpManager,
            LogBuffer logBuffer
    ) {
        mContext = context;
        mTelephonyListenerManager = telephonyListenerManager;
        mConfig = config;
        mMainHandler = handler;
        mReceiverHandler = new Handler(bgLooper);
        mBgLooper = bgLooper;
        mBgExecutor = bgExecutor;
        mCallbackHandler = callbackHandler;
        mStatusBarPipelineFlags = statusBarPipelineFlags;
        mDataSaverController = new DataSaverControllerImpl(context);
        mBroadcastDispatcher = broadcastDispatcher;
        mMobileFactory = mobileFactory;
 
        mSubscriptionManager = subManager;
        mSubDefaults = defaultsHandler;
        mConnectivityManager = connectivityManager;
        mHasMobileDataFeature = telephonyManager.isDataCapable();
        mDemoModeController = demoModeController;
        mCarrierConfigTracker = carrierConfigTracker;
        mDumpManager = dumpManager;
        mLogBuffer = logBuffer;
 
        // telephony
        mPhone = telephonyManager;
 
        // wifi
        mWifiManager = wifiManager;
 
        mLocale = mContext.getResources().getConfiguration().locale;
        mAccessPoints = accessPointController;
        mDataUsageController = dataUsageController;
        mDataUsageController.setNetworkController(this);
        // TODO: Find a way to move this into DataUsageController.
        mDataUsageController.setCallback(new DataUsageController.Callback() {
            @Override
            public void onMobileDataEnabled(boolean enabled) {
                mCallbackHandler.setMobileDataEnabled(enabled);
                notifyControllersMobileDataChanged();
            }
        });
 
        mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
                mCallbackHandler, this, mWifiManager, trackerFactory,
                mReceiverHandler);


注册广播


@VisibleForTesting
    void registerListeners() {
        for (int i = 0; i < mMobileSignalControllers.size(); i++) {
            MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
            mobileSignalController.registerListener();
        }
        if (mSubscriptionListener == null) {
            mSubscriptionListener = new SubListener(mBgLooper);
        }
        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
        mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
 
        // broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        filter.addAction(Intent.ACTION_SERVICE_STATE);
        filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
        filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
        filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
        filter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
        mListening = true;
 
        // Initial setup of connectivity. Handled as if we had received a sticky broadcast of
        // ConnectivityManager.CONNECTIVITY_ACTION.
        mReceiverHandler.post(this::updateConnectivity);
 
        // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast
        // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION
        mReceiverHandler.post(mWifiSignalController::fetchInitialState);
 
        // Initial setup of mLastServiceState. Only run if there is no service state yet.
        // Each MobileSignalController will also get their corresponding
        mReceiverHandler.post(() -> {
            if (mLastServiceState == null) {
                mLastServiceState = mPhone.getServiceState();
                if (mMobileSignalControllers.size() == 0) {
                    recalculateEmergency();
                }
            }
        });
        updateMobileControllers();
 
        // Initial setup of emergency information. Handled as if we had received a sticky broadcast
        // of TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED.
        mReceiverHandler.post(this::recalculateEmergency);
    }


当收到广播时,更新图标


@Override
    public void onReceive(Context context, Intent intent) {
        if (true) {
            Log.d(TAG, "onReceive: intent=" + intent);
        }
        final String action = intent.getAction();
        mLogBuffer.log(
                TAG,
                LogLevel.INFO,
                logMessage -> {
                    logMessage.setStr1(action);
                    return Unit.INSTANCE;
                },
                logMessage -> String.format(
                        Locale.US,
                        "Received broadcast with action \"%s\"",
                        logMessage.getStr1()));
        switch (action) {
            case ConnectivityManager.CONNECTIVITY_ACTION:
                updateConnectivity();
                break;
            case Intent.ACTION_AIRPLANE_MODE_CHANGED:
                refreshLocale();
                updateAirplaneMode(false);
                break;
            case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
                // We are using different subs now, we might be able to make calls.
                recalculateEmergency();
                break;
            case TelephonyManager.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);
                }
                mConfig = Config.readConfig(mContext);
                mReceiverHandler.post(this::handleConfigurationChanged);
                break;
 
            case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: {
                // Notify the relevant MobileSignalController of the change
                int subId = intent.getIntExtra(
                        TelephonyManager.EXTRA_SUBSCRIPTION_ID,
                        INVALID_SUBSCRIPTION_ID
                );
                if (SubscriptionManager.isValidSubscriptionId(subId)) {
                    if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
                        mMobileSignalControllers.get(subId).handleBroadcast(intent);
                    }
                }
            }
            break;
            case Intent.ACTION_SIM_STATE_CHANGED:
                // Avoid rebroadcast because SysUI is direct boot aware.
                if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                    break;
                }
                // Might have different subscriptions now.
                updateMobileControllers();
                break;
            case Intent.ACTION_SERVICE_STATE:
                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;
            case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
                mMainHandler.post(() -> mInternetDialogFactory.create(true,
                        mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(),
                        null /* view */));
                break;
            default:
                int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                        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;
        }
    }


目录
相关文章
|
4月前
|
API Android开发 开发者
Android经典实战之用WindowInsetsControllerCompat方便的显示和隐藏状态栏和导航栏
本文介绍 `WindowInsetsControllerCompat` 类,它是 Android 提供的一种现代化工具,用于处理窗口插入如状态栏和导航栏的显示与隐藏。此类位于 `androidx.core.view` 包中,增强了跨不同 Android 版本的兼容性。主要功能包括控制状态栏与导航栏的显示、设置系统窗口行为及调整样式。通过 Kotlin 代码示例展示了如何初始化并使用此类,以及如何设置系统栏的颜色样式。
235 2
|
4月前
|
Android开发
解决android apk安装后出现2个相同的应用图标
解决android apk安装后出现2个相同的应用图标
379 2
|
4月前
|
API Android开发 Kotlin
Android实战经验分享之如何获取状态栏和导航栏的高度
在Android开发中,掌握状态栏和导航栏的高度对于优化UI布局至关重要。本文介绍两种主要方法:一是通过资源名称获取,简单且兼容性好;二是利用WindowInsets,适用于新版Android,准确性高。文中提供了Kotlin代码示例,并对比了两者的优缺点及适用场景。
379 1
|
4月前
|
XML Android开发 数据格式
Android实战经验之Kotlin中快速实现动态更改应用图标和名称
本文介绍在Android中通过设置多个活动别名动态更改应用图标和名称的方法,涉及XML配置及Kotlin代码示例。
169 10
|
4月前
|
开发工具 Android开发
Android项目架构设计问题之SDK内部减少每次回调时的冗余判断逻辑如何解决
Android项目架构设计问题之SDK内部减少每次回调时的冗余判断逻辑如何解决
44 0
|
4月前
|
Android开发 iOS开发
Android项目架构设计问题之将隐式跳转的逻辑进行抽象和封装如何解决
Android项目架构设计问题之将隐式跳转的逻辑进行抽象和封装如何解决
49 0
|
6月前
|
API Android开发
31. 【Android教程】状态栏通知:Notification
31. 【Android教程】状态栏通知:Notification
593 1
|
6月前
|
存储 Android开发
详细解读Android获取已安装应用信息(图标,名称,版本号,包)
详细解读Android获取已安装应用信息(图标,名称,版本号,包)
91 0
|
7月前
|
Android开发
Android获取当前连接的wifi名称
Android获取当前连接的wifi名称
345 6
|
7月前
|
Java Android开发
Android桌面快捷方式图标生成与删除 使用Intent与launcher交互
Android桌面快捷方式图标生成与删除 使用Intent与launcher交互
125 1