SystemUI 状态栏增加移动数据开启图标

原生设计中,移动数据图标只有在网络活动(下载/上传)时,才显示相应的小白色三角图标,如果没有网络活动则没有任何显示。需要在不活动时也显示灰色的三角图标。

系统导航栏中常见信号图标包括:SIM卡信号(移动数据图标)、WIFI。主要关注几个文件

网络监听控制 NetworkControllerImpl.java

信号变化控制 MobileSignalController.java WifiSignalController.java

图标显示view StatusBarMobileView.java StatusBarWifiView.java

一、增加移动网络非活动状态图标view

在原生基础上,增加一个默认灰色三角图标,启用移动数据时就显示在状态栏中。 

//frameworks/base/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
... ...
        <FrameLayout
            android:id="@+id/inout_container"
            android:layout_height="17dp"
            android:layout_width="wrap_content"
            android:layout_gravity="center_vertical">
            <!-- Add: 增加一层默认图标,使用移动数据时显示 -->
            <ImageView
                android:id="@+id/mobile_open"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/ic_activity_tran"
                android:paddingEnd="2dp"
            />
            <!-- Add -->
            <ImageView
                android:id="@+id/mobile_in"
                android:layout_height="wrap_content"
... ...

 

二、移动网络状态判断

 系统网络发生变化时,会通过广播的方式,通知 NetworkControllerImpl.java 中进行对应变更。

// NetworkControllerImpl.java
    @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 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 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;
            ... ...
        }
    }

NetworkControllerImpl 中对各种网络的各种状态变化进行广播监听,执行相应操作。上面代码中几个Action是SIM相关的。虽然每个执行的方法不同,最后都是执行到 

MobileSignalController.notifyListeners

这里,根据当前信号状态,对图标(IconState)状态进行刷新。原生设计中这里只有activityIn activityOut 标识网络活动,新增加非网络活动的移动数据状态。

//MobileSignalController.java
    public void notifyListeners(SignalCallback callback) {
    ... ...
        boolean activityIn = mCurrentState.dataConnected
                && !mCurrentState.carrierNetworkChangeMode
                && mCurrentState.activityIn;
        boolean activityOut = mCurrentState.dataConnected
                && !mCurrentState.carrierNetworkChangeMode
                && mCurrentState.activityOut;
        showDataIcon &= mCurrentState.isDefault || dataDisabled;
        int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
        // Add: 增加是否是移动网络状态。isDefault 是否是移动数据模式 dataSim 是否是默认数据卡 mobileDataEnabled 移动数据是否开启状态
        Log.d(mTag, "mCurrentState " + mCurrentState);
        statusIcon.connType = (mCurrentState.isDefault && mCurrentState.dataSim && mCurrentState.mobileDataEnabled) ? 1 : 0;
        // Add

        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
                description, icons.mIsWide, mSubscriptionInfo.getSubscriptionId(),
                mCurrentState.roaming);
    }

再交由系统 StatusBarSignalPolicy.java 统一设置到具体的图标状态。对 MobileIconState  也增加一个默认移动数据连接标志 connType,同步更新记录状态。

//StatusBarSignalPolicy.java
    @Override
    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
            int qsType, boolean activityIn, boolean activityOut,
            CharSequence typeContentDescription,
            CharSequence typeContentDescriptionHtml, CharSequence description,
            boolean isWide, int subId, boolean roaming) {
        MobileIconState state = getState(subId);
        if (state == null) {
            return;
        }

        // Add: 同步 statusIcon 图标状态给具体的 MobileIconState
        Log.i(TAG, "setMobileDataIndicators " + statusIcon.connType);
        state.connType = statusIcon.connType;
        // Add

        // Visibility of the data type indicator changed
        boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);

        state.visible = statusIcon.visible && !mBlockMobile;
        state.strengthId = statusIcon.icon;
        state.typeId = statusType;
        state.contentDescription = statusIcon.contentDescription;
        state.typeContentDescription = typeContentDescription;
        state.roaming = roaming;
        state.activityIn = activityIn && mActivityEnabled;
        state.activityOut = activityOut && mActivityEnabled;

        // Always send a copy to maintain value type semantics
        mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
    }

... ...

    public static class MobileIconState extends SignalIconState {
    ... ...
        public CharSequence typeContentDescription;
        public int connType;//Add: 使用移动数据
    ... ...

        @Override
        public boolean equals(Object o) {
        ... ...
            return subId == that.subId &&
                    strengthId == that.strengthId &&
                    typeId == that.typeId &&
                    roaming == that.roaming &&
                    needsLeadingPadding == that.needsLeadingPadding &&
                    Objects.equals(typeContentDescription, that.typeContentDescription)&&
                    // Modify: 增加变量 connType
                    connType == that.connType;
        }

        @Override
        public int hashCode() {
            // Modify: 增加变量 connType
            return Objects
                    .hash(super.hashCode(), subId, strengthId, typeId, roaming, needsLeadingPadding, typeContentDescription, connType);
        }
    ... ...

        public void copyTo(MobileIconState other) {
        ... ...
            other.needsLeadingPadding = needsLeadingPadding;
            other.typeContentDescription = typeContentDescription;
            //Add: 增加变量 connType
            other.connType = connType;
        }
    ... ...

        @Override public String toString() {
            // Modify: 增加变量 connType
            return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
                    + roaming + ", typeId=" + typeId + ", visible=" + visible + ", connType=" + connType + ")";
        }
    }

继续 setMobileIcons 设置刷新 MobileIconState 流程:

StatusBarIconControllerImpl.setMobileIcons -> StatusBarIconControllerImpl.handleSet -> StatusBarIconController.onSetIconHolder -> StatusBarIconController.onSetMobileIcon

这一段不需要修改,作用就是将 MobileIconState 状态传到 StatusBarMobileView 中。

//StatusBarIconController.java
        public void onSetMobileIcon(int viewIndex, MobileIconState state) {
            StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex);
            if (view != null) {
                view.applyMobileState(state);
            }

            if (mIsInDemoMode) {
                mDemoStatusIcons.updateMobileState(state);
            }
        }

在 StatusBarMobileView 中根据 MobileIconState 状态数据进行刷新。需要修改两处:初始化及更新的函数。

//StatusBarMobileView.java
    private void initViewState() {
    ... ...
         mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
         mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
         //Modify: 根据 MobileIconState 中状态,控制图标
         //mInoutContainer.setVisibility((mState.activityIn || mState.activityOut)
         mInoutContainer.setVisibility(mState.connType == 1
                 ? View.VISIBLE : View.GONE);
    ... ...
    }

    private boolean updateState(MobileIconState state) {
    ... ...
         mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
         mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
         //Modify: 根据 MobileIconState 中状态,控制图标
         // mInoutContainer.setVisibility((state.activityIn || state.activityOut)
         Log.i(TAG, "updateState " + state.connType);
         mInoutContainer.setVisibility(state.connType == 1
                 ? View.VISIBLE : View.GONE);
    ... ...
    }

    原文作者:虫师魁拔
    原文地址: https://blog.csdn.net/tq501501/article/details/123902619
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞