Android 10.0 顶部状态栏系统图标显示分析

简介: Android 10.0 顶部状态栏系统图标显示分析

这里StatuBar的创建就不说了,前面已经说过了。

SystemUI中StatusBar的图标控制器实现类为StatusBarIconControllerImpl,其继承了StatusBarIconController的接口,用于跟踪所有图标的状态,并将对应的状态发送给注册的图标管理器(IconManagers)。当我们在StatusBar中获取到它的实例后,还会将它传给PhoneStatusBarPolicy和StatusBarSignalPolicy对象。PhoneStatusBarPolicy控制启动时装载哪些图标(蓝牙,定位等),而StatusBarSignalPolicy控制网络信号图标(移动网络,WiFi,以太网)的变化。

一起来看 StatuBar 的 start() 方法:

@Override
public void start() {
    // 省略部分代码......
    // 创建整个SystemUI视图并添加到WindowManager中
    createAndAddWindows();//这个重点方法,创建相关的视图
    // 省略部分代码......
    // Lastly, call to the icon policy to install/update all the icons.
    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
    @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);
        // broadcasts
        IntentFilter filter = new IntentFilter();
        // wifi相关
        // wifi信号强度广播
        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        // wifi状态变化广播
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        // wifi连接状态改变
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        // 移动网络相关
        // SIM卡状态改变
        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;
        // 省略部分代码......
        // 4.更新移动网络控制器
        updateMobileControllers();
    }

在NetworkControllerImpl 的构造方法里,最终会调用到:registerListeners() 方法进行广播的注册。

广播处理:

@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:
                // We are using different subs now, we might be able to make calls.
                 // 省略部分代码......
                break;
            case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
                // Notify every MobileSignalController so they can know whether they are the
                // data sim or not.
                // 省略部分代码......
                break;
            case Intent.ACTION_SIM_STATE_CHANGED:
                // Avoid rebroadcast because SysUI is direct boot aware.
                // 省略部分代码......
                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 {
                        // Can't find this subscription...  We must be out of date.
                        updateMobileControllers();
                    }
                } else {
                     // wifi状态图标处理
                    // No sub id, must be for the wifi.
                    mWifiSignalController.handleBroadcast(intent);
                }
                break;
        }
    }

这里以 wifi状态图标处理 为例;接下来看WifiSignalController#handleBroadcast():

// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java 
    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 
    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
    @Override
    public void notifyListeners(SignalCallback callback) {
        // only show wifi in the cluster if connected or if wifi-only
        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为 CallbackHandler对象
        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
    @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():

/**
     * 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);
        }
    }

首先设置WiFi的状态信息,遍历mIconGroups分别执行StatusBarIconController接口中静态类IconManager中的onIconAdded()和onSetIconHolder()的回调。

IconManager用于将信息从StatusBarIconController转换为ViewGroup中的ImageViews(com.android.systemui.statusbar.AlphaOptimizedImageView)。

接着看IconManager中的onIconAdded()和onSetIconHolder()方法:这两个方法一个用于添加、一个用于更新。

public interface StatusBarIconController {
    ....
    public static class DarkIconManager extends IconManager {
        ....
        public DarkIconManager(LinearLayout linearLayout) {
            // 将布局传入IconManager
            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) {
            // 调用到父类的addHolder方法
            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 
            StatusBarWifiView view = onCreateStatusBarWifiView(slot);
            view.applyWifiState(state);
            // 将view 添加进ViewGroup
            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状态栏图标根据源码可大体分为三种:

  1. StatusBarIconView

  2. StatusBarWifiView

  3. StatusBarMobileView

这里主要以Wifi 相关图标(StatusBarWifiView)进行分析,添加Icon时首先会创建一个

StatusBarWifiView,然后调用StatusBarWifiView的applyWifiState更新其显示状态,最后将其加入到CollapsedStatusBarFragment中放置Icon的ViewGroup中,这样就完成了添加过程;

再来看看 CollapsedStatusBarFragment:

// SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
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) {
        ....
        // 这里可以看出status_bar布局中的statusIcons就是我们展示各种Icon的区域
        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
        mDarkIconManager.setShouldLog(true);
        Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
        ....   
    }
}
补充:

  notifyListenersIfNecessary()在其父类SignalController中定义,

// SignalController.java
    private final CallbackHandler mCallbackHandler;
    public void notifyListenersIfNecessary() {
        if (isDirty()) {
            saveLastState();
            notifyListeners();
        }
    }
    // 在这里注意了,在这里的的参数是 CallbackHandler 的对象
    public final void notifyListeners() {
        notifyListeners(mCallbackHandler);
    }
// callback 则是 CallbackHandler 的对象。
  public abstract void notifyListeners(SignalCallback callback);

  CallbackHandler维护了所有需要监听的SignalCallback接口对象,我们的StatusBarSignalPolicy就实现了该接口。

  StatusBarSignalPolicy主要执行网络图标的刷新动作,其实现了NetworkControllerImpl.SignalCallback接口,然后注册到NetworkController,其具体实现类NetworkControllerImpl会根据WIFI,SIM等状态广播来进一步派发给具体的Controller,例如WifiSignalController,每个Controller只与CallbackHandler交互,然后CallbackHandler继续转交给维护的SignalCallback接口的具体实现类,例如StatusBarSignalPolicy

相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
166 4
|
1月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
23天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
26天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
30 8
|
24天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
1月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
70 16
|
1月前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
38 1
|
22天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
46 19