Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(上)

简介: Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新

SystemUI系列文章


Android8.1 MTK平台 SystemUI源码分析之 Notification流程

Android8.1 MTK平台 SystemUI源码分析之 电池时钟刷新

Android 8.1平台SystemUI 导航栏加载流程解析


一、从布局说起


前面的文章分析过,网络信号栏这块属于 system_icon_area,里面包含蓝牙、wifi、VPN、网卡、SIM卡网络类型、

数据流量符号、SIM卡信号格、电池、时钟。


先来看下 system_icon_area 对应的布局文件 system_icons.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">
    <com.android.keyguard.AlphaOptimizedLinearLayout 
    android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>
    <include layout="@layout/signal_cluster_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>
    <com.android.systemui.BatteryMeterView 
    android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        />
</LinearLayout>

看到里面的 signal_cluster_view.xml 正是我们要找的信号栏布局文件,内容有点多,下面只截取我们关心的


vendor\mediatek\proprietary\packages\apps\SystemUI\res\layout\signal_cluster_view.xml

<com.android.systemui.statusbar.SignalClusterView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/signal_cluster"
    android:layout_height="match_parent"
    android:layout_width="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingEnd="@dimen/signal_cluster_battery_padding"
    >
   ... vpn 
   ... 网卡
   ... wifi
  手机信号栏
    <LinearLayout
        android:id="@+id/mobile_signal_group"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        >
    </LinearLayout>
  未插入SIM卡
    <FrameLayout
        android:id="@+id/no_sims_combo"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:contentDescription="@string/accessibility_no_sims">
        <com.android.systemui.statusbar.AlphaOptimizedImageView
            android:theme="?attr/lightIconTheme"
            android:id="@+id/no_sims"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:src="@drawable/stat_sys_no_sims"
            />
        <com.android.systemui.statusbar.AlphaOptimizedImageView
            android:theme="?attr/darkIconTheme"
            android:id="@+id/no_sims_dark"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:src="@drawable/stat_sys_no_sims"
            android:alpha="0.0"
            />
    </FrameLayout>
    <View
        android:id="@+id/wifi_airplane_spacer"
        android:layout_width="@dimen/status_bar_airplane_spacer_width"
        android:layout_height="4dp"
        android:visibility="gone"
        />
  飞行模式
    <ImageView
        android:id="@+id/airplane"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        />
</com.android.systemui.statusbar.SignalClusterView>


可以看到最外层是自定义 SignalClusterView,xml里包含了 vpn、网卡、wifi、手机信号栏、未插入SIM卡、飞行模式对应的 view,那么接下来看下 SignalClusterView 代码


vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\SignalClusterView.java

public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback, SecurityController.SecurityControllerCallback, Tunable,DarkReceiver 
public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    Resources res = getResources();
    mMobileSignalGroupEndPadding =
            res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
    mMobileDataIconStartPadding =
            res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
    mWideTypeIconStartPadding = res.getDimensionPixelSize(R.dimen.wide_type_icon_start_padding);
    mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
    mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
    mEndPaddingNothingVisible = res.getDimensionPixelSize(
            R.dimen.no_signal_cluster_battery_padding);
    TypedValue typedValue = new TypedValue();
    res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
    mIconScaleFactor = typedValue.getFloat();
  //网络相关控制器
    mNetworkController = Dependency.get(NetworkController.class);
  //安全相关控制器
    mSecurityController = Dependency.get(SecurityController.class);
    updateActivityEnabled();
    /// M: Add for Plugin feature @ {
    mStatusBarExt = OpSystemUICustomizationFactoryBase.getOpFactory(context)
                                 .makeSystemUIStatusBar(context);
    /// @ }
    mIsWfcEnable = SystemProperties.get("persist.mtk_wfc_support").equals("1");
}

看到 SignalClusterView 继承自 LinearLayout,实现了 NetworkController、SecurityController(这俩类控制图标的刷新逻辑)


构造方法中通过 Dependency.get() 实例化 NetworkController、SecurityController这俩核心


类,跟进 Dependent 类中大概看了下 get()方法,其实就是通过单例模式来进行管理,里面维护了一


个数据类型为 ArrayMap 的 DependencyProvider 集合对象,通过 put和 get 来存取。


接着回到 SignalClusterView 中看下控件都是怎么初始化的?

 @Override
protected void onFinishInflate() {
    super.onFinishInflate();
    mVpn            = findViewById(R.id.vpn);
    mEthernetGroup  = findViewById(R.id.ethernet_combo);
    mEthernet       = findViewById(R.id.ethernet);
    mEthernetDark   = findViewById(R.id.ethernet_dark);
    mWifiGroup      = findViewById(R.id.wifi_combo);
    mWifi           = findViewById(R.id.wifi_signal);
    mWifiDark       = findViewById(R.id.wifi_signal_dark);
    mWifiActivityIn = findViewById(R.id.wifi_in);
    mWifiActivityOut= findViewById(R.id.wifi_out);
    mAirplane       = findViewById(R.id.airplane);
    mNoSims         = findViewById(R.id.no_sims);
    mNoSimsDark     = findViewById(R.id.no_sims_dark);
    mNoSimsCombo    =             findViewById(R.id.no_sims_combo);
    mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
    mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
    mMobileSignalGroup =          findViewById(R.id.mobile_signal_group);
    maybeScaleVpnAndNoSimsIcons();
}


这里初始化了一堆刚刚布局文件里的控件,onFinishInflate() 在 xml 布局文件被加载完成后就会调


用,我们看到布局文件中都没有给控件设置对应的 background icon,而且有的 visibility 为


gone,那么信号栏图标是如何设置对应的icon和显示的呢?


二、SignalCluterView 详解


20190527212955195.png



SignalCluterView 中调用频率很高的方法 apply() 就是幕后黑手,通过该方法控制一系列图标的更


新, 然而 SignalCallback 的如下每个回调最终都调用 apply()


1、setWifiIndicators() wifi开关状态、流量上下行

2、setMobileDataIndicators() 手机网络类型、信号强度、流量上下行、volte图标

3、setSubs() SIM卡识别结束

4、setNoSims() 未插入SIM卡状态

5、setEthernetIndicators() 网卡状态

6、setIsAirplaneMode() 飞行模式是否打开

7、setMobileDataEnabled() SIM卡数据流量是否开启


1、apply()

private void apply() {
    if (mWifiGroup == null) return;
  //vpn图标
    if (mVpnVisible) {
        if (mLastVpnIconId != mVpnIconId) {
            setIconForView(mVpn, mVpnIconId);
            mLastVpnIconId = mVpnIconId;
        }
        mIconLogger.onIconShown(SLOT_VPN);
        mVpn.setVisibility(View.VISIBLE);
    } else {
        mIconLogger.onIconHidden(SLOT_VPN);
        mVpn.setVisibility(View.GONE);
    }
    if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
    //网卡图标
    if (mEthernetVisible) {
        if (mLastEthernetIconId != mEthernetIconId) {
            setIconForView(mEthernet, mEthernetIconId);
            setIconForView(mEthernetDark, mEthernetIconId);
            mLastEthernetIconId = mEthernetIconId;
        }
        mEthernetGroup.setContentDescription(mEthernetDescription);
        mIconLogger.onIconShown(SLOT_ETHERNET);
        mEthernetGroup.setVisibility(View.VISIBLE);
    } else {
        mIconLogger.onIconHidden(SLOT_ETHERNET);
        mEthernetGroup.setVisibility(View.GONE);
    }
    if (DEBUG) Log.d(TAG,
            String.format("ethernet: %s",
                (mEthernetVisible ? "VISIBLE" : "GONE")));
  //wifi图标
    if (mWifiVisible) {
        if (mWifiStrengthId != mLastWifiStrengthId) {
            setIconForView(mWifi, mWifiStrengthId);
            setIconForView(mWifiDark, mWifiStrengthId);
            mLastWifiStrengthId = mWifiStrengthId;
        }
        mIconLogger.onIconShown(SLOT_WIFI);
        mWifiGroup.setContentDescription(mWifiDescription);
        mWifiGroup.setVisibility(View.VISIBLE);
    } else {
        mIconLogger.onIconHidden(SLOT_WIFI);
        mWifiGroup.setVisibility(View.GONE);
    }
    if (DEBUG) Log.d(TAG,
            String.format("wifi: %s sig=%d",
                (mWifiVisible ? "VISIBLE" : "GONE"),
                mWifiStrengthId));
  //wifi数据上下行图标
    mWifiActivityIn.setVisibility(mWifiIn ? View.VISIBLE : View.GONE);
    mWifiActivityOut.setVisibility(mWifiOut ? View.VISIBLE : View.GONE);
    boolean anyMobileVisible = false;
    /// M: Support for [Network Type on Statusbar]
    /// A spacer is set between networktype and WIFI icon @ {
    if (FeatureOptions.MTK_CTA_SET) {
        anyMobileVisible = true;
    }
    /// @ }
  //SIM 卡组图标
    int firstMobileTypeId = 0;
    for (PhoneState state : mPhoneStates) {
    //PhoneState中的另一个apply()方法,对应网络类型、信号格等
        if (state.apply(anyMobileVisible)) {
            if (!anyMobileVisible) {
                firstMobileTypeId = state.mMobileTypeId;
                anyMobileVisible = true;
            }
        }
    }
    if (anyMobileVisible) {
        mIconLogger.onIconShown(SLOT_MOBILE);
    } else {
        mIconLogger.onIconHidden(SLOT_MOBILE);
    }
  //飞行模式图标
    if (mIsAirplaneMode) {
        if (mLastAirplaneIconId != mAirplaneIconId) {
            setIconForView(mAirplane, mAirplaneIconId);
            mLastAirplaneIconId = mAirplaneIconId;
        }
        mAirplane.setContentDescription(mAirplaneContentDescription);
        mIconLogger.onIconShown(SLOT_AIRPLANE);
        mAirplane.setVisibility(VISIBLE);
    } else {
        mIconLogger.onIconHidden(SLOT_AIRPLANE);
        mAirplane.setVisibility(View.GONE);
    }
  //wifi和飞行模式间隔
    if (mIsAirplaneMode && mWifiVisible) {
        mWifiAirplaneSpacer.setVisibility(View.VISIBLE);
    } else {
        mWifiAirplaneSpacer.setVisibility(View.GONE);
    }
    if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) {
        mWifiSignalSpacer.setVisibility(View.VISIBLE);
    } else {
        mWifiSignalSpacer.setVisibility(View.GONE);
    }
  //未插入SIM卡图标组
    if (mNoSimsVisible) {
        mIconLogger.onIconShown(SLOT_MOBILE);
        mNoSimsCombo.setVisibility(View.VISIBLE);
        if (!Objects.equals(mSimDetected, mNoSimsCombo.getTag())) {
            mNoSimsCombo.setTag(mSimDetected);
            /// M:alps03596830 Don't show lack of signal when airplane mode is on.
            if (mSimDetected && !mIsAirplaneMode) {
                SignalDrawable d = new SignalDrawable(mNoSims.getContext());
                d.setDarkIntensity(0);
                mNoSims.setImageDrawable(d);
                mNoSims.setImageLevel(SignalDrawable.getEmptyState(4));
                SignalDrawable dark = new SignalDrawable(mNoSims.getContext());
                dark.setDarkIntensity(1);
                mNoSimsDark.setImageDrawable(dark);
                mNoSimsDark.setImageLevel(SignalDrawable.getEmptyState(4));
            } else {
                mNoSims.setImageResource(R.drawable.stat_sys_no_sims);
                mNoSimsDark.setImageResource(R.drawable.stat_sys_no_sims);
            }
        }
    } else {
        mIconLogger.onIconHidden(SLOT_MOBILE);
        mNoSimsCombo.setVisibility(View.GONE);
    }
    /// M: Add for Plugin feature @ {
    mStatusBarExt.setCustomizedNoSimsVisible(mNoSimsVisible);
    mStatusBarExt.setCustomizedAirplaneView(mNoSimsCombo, mIsAirplaneMode);
    /// @ }
    boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
            || anyMobileVisible || mVpnVisible || mEthernetVisible;
    setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
}


通过上面的代码发现 apply 控制了 VPN、网卡、wifi、飞行模式、未插入SIM 这几种图标的显示和隐

藏,我们看到里面有另外一个 state.apply(anyMobileVisible) 用来控制 SIM卡相关的图标,接下

来看下都有哪些图标呢?


2、内部类 PhoneState


PhoneState 是 SignalClusterView 中一个内部类,控制volte、网络类型、数据是否打开、信号格

数、漫游等图标

private class PhoneState {
  //SIM卡id
    private final int mSubId;
  //SIM卡组是否可见
    private boolean mMobileVisible = false;
  //信号格数图标、数据流量是否打开图标(关闭是X,打开是网络类型小图标4G/3G)
    private int mMobileStrengthId = 0, mMobileTypeId = 0;
    ///M: Add for [Network Type and volte on Statusbar]
  //网络类型图标
    private int mNetworkIcon = 0;
  //volte图标
    private int mVolteIcon = 0;
    private int mLastMobileStrengthId = -1;
    private int mLastMobileTypeId = -1;
    private boolean mIsMobileTypeIconWide;
  //网络类型描述,运营商类型,或只能拨打紧急号码
    private String mMobileDescription, mMobileTypeDescription;
  //整个PhoneState根本局,SIM信号栏组
    private ViewGroup mMobileGroup;
  //信号格控件、流量图标控件、是否漫游控件
    private ImageView mMobile, mMobileDark, mMobileType, mMobileRoaming;
    public boolean mRoaming;
  //手机流量上下行控件
    private ImageView mMobileActivityIn;
    private ImageView mMobileActivityOut;
    public boolean mActivityIn;
    public boolean mActivityOut;
    /// M: Add for new features @ {
    // Add for [Network Type and volte on Statusbar]
  //网络类型控件
    private ImageView mNetworkType;
  //volte控件
    private ImageView mVolteType;
    private boolean mIsWfcCase;
    /// @ }
    /// M: Add for plugin features. @ {
    private boolean mDataActivityIn, mDataActivityOut;
    private ISystemUIStatusBarExt mPhoneStateExt;
    /// @ }
    public PhoneState(int subId, Context context) {
    //加载 mobile_signal_group_ext 布局文件
        ViewGroup root = (ViewGroup) LayoutInflater.from(context)
                .inflate(R.layout.mobile_signal_group_ext, null);
        /// M: Add data group for plugin feature. @ {
        mPhoneStateExt = OpSystemUICustomizationFactoryBase.getOpFactory(context)
                            .makeSystemUIStatusBar(context);
        mPhoneStateExt.addCustomizedView(subId, context, root);
        /// @ }
        setViews(root);
        mSubId = subId;
    }
  //控件初始化
    public void setViews(ViewGroup root) {
        mMobileGroup    = root;
        mMobile         = root.findViewById(R.id.mobile_signal);
        mMobileDark     = root.findViewById(R.id.mobile_signal_dark);
        mMobileType     = root.findViewById(R.id.mobile_type);
       ///M: Add for [Network Type and volte on Statusbar]
        mNetworkType    = (ImageView) root.findViewById(R.id.network_type);
        mVolteType      = (ImageView) root.findViewById(R.id.volte_indicator_ext);
        mMobileRoaming  = root.findViewById(R.id.mobile_roaming);
        mMobileActivityIn = root.findViewById(R.id.mobile_in);
        mMobileActivityOut = root.findViewById(R.id.mobile_out);
        // TODO: Remove the 2 instances because now the drawable can handle darkness.
        mMobile.setImageDrawable(new SignalDrawable(mMobile.getContext()));
        SignalDrawable drawable = new SignalDrawable(mMobileDark.getContext());
        drawable.setDarkIntensity(1);
        mMobileDark.setImageDrawable(drawable);
    }
    public boolean apply(boolean isSecondaryIcon) {
        Log.e(TAG, "apply()  mMobileVisible = " + mMobileVisible
                            + ", mIsAirplaneMode = " + mIsAirplaneMode
                            + ", mIsWfcEnable = " + mIsWfcEnable
                            + ", mIsWfcCase = " + mIsWfcCase
                            + ", mVolteIcon = " + mVolteIcon);
        if (mMobileVisible && !mIsAirplaneMode) {
             Log.e(TAG, "apply() into this code 1.. mMobileStrengthId=="+mMobileStrengthId);
      //设置信号格数
            if (mLastMobileStrengthId != mMobileStrengthId) {
                mMobile.getDrawable().setLevel(mMobileStrengthId);
                mMobileDark.getDrawable().setLevel(mMobileStrengthId);
                mLastMobileStrengthId = mMobileStrengthId;
            }
      //设置流量是否打开
            if (mLastMobileTypeId != mMobileTypeId) {
                if (!mPhoneStateExt.disableHostFunction()) {
                    mMobileType.setImageResource(mMobileTypeId);
                }
                mLastMobileTypeId = mMobileTypeId;
            }
            mMobileGroup.setContentDescription(mMobileTypeDescription
                    + " " + mMobileDescription);
            mMobileGroup.setVisibility(View.VISIBLE);
            showViewInWfcCase();
        } else {
            if (mIsAirplaneMode && (mIsWfcEnable && mVolteIcon != 0)) {
                 Log.e(TAG, "apply() into this code 2..");
                /// M:Bug fix for show vowifi icon in flight mode
                mMobileGroup.setVisibility(View.VISIBLE);
                hideViewInWfcCase();
            } else {
                 Log.e(TAG, "apply() into this code 3..");
                if (DEBUG) {
                    Log.d(TAG, "setVisibility as GONE, this = " + this
                            + ", mMobileVisible = " + mMobileVisible
                            + ", mIsAirplaneMode = " + mIsAirplaneMode
                            + ", mIsWfcEnable = " + mIsWfcEnable
                            + ", mVolteIcon = " + mVolteIcon);
                }
                mMobileGroup.setVisibility(View.GONE);
            }
        }
        /// M: Set all added or customised view. @ {
    //更新网络类型和volte图标
        setCustomizeViewProperty();
        /// @ }
        // When this isn't next to wifi, give it some extra padding between the signals.
        mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
                0, 0, 0);
        mMobile.setPaddingRelative(
                mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
                0, 0, 0);
        mMobileDark.setPaddingRelative(
                mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
                0, 0, 0);
        if (true) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
                    (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
         Log.e(TAG, "mActivityIn="+mActivityIn+" mActivityOut="+mActivityOut);   
        if(!mIsWfcCase) {
            //更新流量是否打开可见性
            mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE :View.GONE);
      //漫游图标
            mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
      //流量上下行图标
            mMobileActivityIn.setVisibility(mActivityIn ? View.VISIBLE : View.GONE);
            mMobileActivityOut.setVisibility(mActivityOut ? View.VISIBLE : View.GONE);
        }
        /// M: Add for support plugin featurs. @ {
    //可通过op01/2/3等加载SystemUI,从6.0延伸来的
        setCustomizedOpViews();
        /// @ }
        return mMobileVisible;
    }
 ......
}


PhoneState 中的成员变量较多,我在代码里都已经加了注释了,就不细说了。加载的布局文件为


vendor\mediatek\proprietary\packages\apps\SystemUI\res_ext\layout\mobile_signal_group_ext.xml


<?xml version="1.0" encoding="utf-8"?>
<!-- Support [Network Type on Statusbar] The layout to wrap original
mobile_signal_group and add image view for show network Type -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    >
    <ImageView
        android:id="@+id/volte_indicator_ext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        />
    <ImageView
        android:id="@+id/network_type"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:visibility="gone"
        /> 
    <include layout="@layout/mobile_signal_group"/>
</LinearLayout>


布局文件中对应了 volte 和当前网络类型大图标, 再包含了 mobile_signal_group,里面就是上面提到的各种控件


vendor\mediatek\proprietary\packages\apps\SystemUI\res\layout\mobile_signal_group.xml


3、state.apply(anyMobileVisible) 调用流程


通过上面的分析可以总结下 信号栏的调用流程


NetworkControllerImpl.java 中注册了SIM卡状态改变广播(ACTION_SIM_STATE_CHANGED),当收


到广播通知后调用到 notifyAllListeners()


通知所有的监听,mobileSignalController、mWifiSignalController、


mEthernetSignalController,分别对应手机信号显示、wifi信号、网卡显示通知


我们看到 mobileSignalController 中的回调 notifyListeners(SignalCallback callback),


在进行一系列的赋值操作后,最终回调到


SignalClusterView 中的 setMobileDataIndicators(),给 PhoneState 的成员变量赋值,


最后通过 apply()进行更新


4、PhoneState创建


通过刚刚对 PhoneState 类的介绍,发现通过构造方法 PhoneState(int subId, Context context) 可获取 PhoneState 对象


搜索当前文件找到在 inflatePhoneState(int subId) 中实例化 PhoneState

@Override
public void setSubs(List<SubscriptionInfo> subs) {
    if (DEBUG) {
        Log.d(TAG, "setSubs, this = " + this + ", size = " + subs.size()
            + ", subs = " + subs);
    }
    if (hasCorrectSubs(subs)) {//判断SIM卡是否改变
        if (DEBUG) {
            Log.d(TAG, "setSubs, hasCorrectSubs and return");
        }
        return;
    }
    mPhoneStates.clear();
    if (mMobileSignalGroup != null) {
        mMobileSignalGroup.removeAllViews();//移除手机信号组中的所有view 
    }
    final int n = subs.size();//SIM卡数量
    Log.d(TAG, "setSubs-clear subsize:" + subs.size() + "mStes" + mPhoneStates + ":" + this);
    for (int i = 0; i < n; i++) {
        inflatePhoneState(subs.get(i).getSubscriptionId());
    }
    if (isAttachedToWindow()) {
        applyIconTint();//图标根据背景色动态变化
    }
}
private PhoneState inflatePhoneState(int subId) {
    PhoneState state = new PhoneState(subId, mContext);
    if (mMobileSignalGroup != null) {
        mMobileSignalGroup.addView(state.mMobileGroup);//添加view到手机信号组中
    }
    Log.d(TAG, "inflatePhoneState add subId:" + subId + ",state" + state + ":" + this);
    mPhoneStates.add(state);//存储PhoneState 对象,方便快速修改状态
    return state;
}



当SIM卡插入识别后将回调 setSubs(),先判断SIM卡是否改变,有效则移除 mobileGroup 中已添加


所有view,遍历SIM卡数量,通过 subId 创建 PhoneState,并将对应的view添加到 mobileGroup 中。


然后将 PhoneState对象存储到集合中,方便快速修改状态


这里简单说下 subId subid对应卡,slotid对应卡槽


slotid或者phoneid是指卡槽,双卡机器的卡槽1值为0,卡槽2值为1,依次类推


subid的值从1开始,每插入一个新卡,subId的值就会加1。


插入双卡后数据库中就会有subid值为1和2的两个数据条目,


拔卡插卡交换卡槽后,数据库并不会增加新项,只有插入一张新的sim卡才会增加一条id为3的数据条目


详细的介绍请看这篇 subId、slotId

目录
相关文章
|
1月前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求处理
【2月更文挑战第30天】 在移动应用开发领域,网络请求的处理是影响用户体验的关键环节。针对Android平台,利用Kotlin协程能够极大提升异步任务处理的效率和简洁性。本文将探讨如何通过Kotlin协程优化Android应用中的网络请求处理流程,包括协程的基本概念、网络请求的异步执行以及错误处理等方面,旨在帮助开发者构建更加流畅和响应迅速的Android应用。
|
2月前
|
Android开发
安卓SO层开发 -- 编译指定平台的SO文件
安卓SO层开发 -- 编译指定平台的SO文件
33 0
|
4天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
12天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
11 0
|
12天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
10 0
|
1月前
|
运维 监控 Java
应用研发平台EMAS产品常见问题之安卓构建版本失败如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
|
1月前
|
运维 监控 Android开发
应用研发平台EMAS常见问题之安卓push的离线转通知目前无法收到如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
25 1
|
2月前
|
网络协议 物联网 Linux
WireGuard 系列文章(五):Netmaker 简介 - 创建和管理 WireGuard 网络的平台
WireGuard 系列文章(五):Netmaker 简介 - 创建和管理 WireGuard 网络的平台
【计算机网络】物理链路通信信号
【1月更文挑战第27天】【计算机网络】物理链路通信信号
|
3月前
|
编解码 测试技术 开发工具
如何实现Android视音频数据对接到GB28181平台(SmartGBD)
如何实现Android视音频数据对接到GB28181平台(SmartGBD)