美文网首页
Android 8.0 状态栏信号显示、信号定制

Android 8.0 状态栏信号显示、信号定制

作者: 江丶小鱼 | 来源:发表于2018-07-05 19:21 被阅读0次

    之前发了下拉通知栏开关修改的一篇文章。
    这篇文章呢,主要介绍一下Android状态栏信号图标显示的流程。
    便于在Android源生上开发的碰到问题的朋友,希望能对读者有所帮助。内容可能比较长
    首先还是先介绍布局。

    一、状态栏信号布局

    路径:android\frameworks\base\packages\SystemUI\res\layout\status_bar.xml
    如下代码就是状态栏的布局,包含:时钟、通知、system_icons等。

    <?xml version="1.0" encoding="utf-8"?>
    <com.android.systemui.statusbar.phone.PhoneStatusBarView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
        android:layout_width="match_parent"
        android:layout_height="@dimen/status_bar_height"
        android:id="@+id/status_bar"
        android:background="@drawable/system_bar_background"
        android:orientation="vertical"
        android:focusable="false"
        android:descendantFocusability="afterDescendants"
        >
    
        <ImageView
            android:id="@+id/notification_lights_out"
            android:layout_width="@dimen/status_bar_icon_size"
            android:layout_height="match_parent"
            android:paddingStart="6dip"
            android:paddingBottom="2dip"
            android:src="@drawable/ic_sysbar_lights_out_dot_small"
            android:scaleType="center"
            android:visibility="gone"
            />
    
        <LinearLayout android:id="@+id/status_bar_contents"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingStart="6dp"
            android:paddingEnd="8dp"
            android:orientation="horizontal"
            >
    
            <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
                 PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
            <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
                android:id="@+id/notification_icon_area"
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="horizontal" />
    
            <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal"
                >
                <include layout="@layout/system_icons" />
                <com.android.systemui.statusbar.policy.Clock
                    android:id="@+id/clock"
    
         android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:singleLine="true"
                    android:paddingStart="@dimen/status_bar_clock_starting_padding"
                    android:paddingEnd="@dimen/status_bar_clock_end_padding"
                    android:gravity="center_vertical|start"
                    />
            </com.android.keyguard.AlphaOptimizedLinearLayout>
        </LinearLayout>
        <ViewStub
            android:id="@+id/emergency_cryptkeeper_text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout="@layout/emergency_cryptkeeper_text"
        />
    </com.android.systemui.statusbar.phone.PhoneStatusBarView>
    

    ~
    ~
    system_icons:信号区域:signal_cluster_view、状态栏电池,statusIcons(蓝牙、飞行模式statusIcons)。
    system_icons内容如下图:

    <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="wrap_content"
            />
    </LinearLayout>
    

    ~
    signal_cluster_view有对应的布局,代码上写了,内容如下,内容较多、我就只截取部分展示了。其中mobile_signal_group就是信号区域了,它也对应一个布局 mobile_signal_group.xmlmobile_signal_group中主要是信号图标、数据流量箭头等位置显示了。

       <LinearLayout
           android:id="@+id/mobile_signal_group"
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           >
       </LinearLayout>
       <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>
    

    ~

    mobile_signal_group.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:systemui="http://schemas.android.com/apk/res-auto"
        android:id="@+id/mobile_combo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="2dp"
            android:id="@+id/data_inout"
            android:visibility="gone"
            />
        <FrameLayout
            android:layout_height="17dp"
            android:layout_width="wrap_content">
            <ImageView
                android:id="@+id/mobile_in"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/ic_activity_down"
                android:visibility="gone"
                android:paddingEnd="2dp"
                />
            <ImageView
                android:id="@+id/mobile_out"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/ic_activity_up"
                android:paddingEnd="2dp"
                android:visibility="gone"
                />
        </FrameLayout>
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            >
            <FrameLayout
                android:id="@+id/mobile_signal_single"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <com.android.systemui.statusbar.AnimatedImageView
                    android:theme="@style/DualToneLightTheme"
                    android:id="@+id/mobile_signal"
                    android:layout_height="wrap_content"
                    android:layout_width="wrap_content"
                    systemui:hasOverlappingRendering="false"
                    />
                <com.android.systemui.statusbar.AnimatedImageView
                    android:theme="@style/DualToneDarkTheme"
                    android:id="@+id/mobile_signal_dark"
                    android:layout_height="wrap_content"
                    android:layout_width="wrap_content"
                    android:alpha="0.0"
                    systemui:hasOverlappingRendering="false"
                    />
                <ImageView
                    android:id="@+id/mobile_type"
                    android:layout_height="wrap_content"
                    android:layout_width="wrap_content"
                    />
                <ImageView
                    android:id="@+id/mobile_roaming"
                    android:layout_width="wrap_content"
                    android:layout_height="17dp"
                    android:paddingStart="22dp"
                    android:paddingTop="1.5dp"
                    android:paddingBottom="3dp"
                    android:scaleType="fitCenter"
                    android:src="@drawable/stat_sys_roaming"
                    android:contentDescription="@string/accessibility_data_connection_roaming"
                    android:visibility="gone" />
            </FrameLayout>
            <LinearLayout
                android:id="@+id/mobile_signal_stacked"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:visibility="gone"
                >
                <ImageView
                    android:id="@+id/mobile_signal_data"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    />
                <ImageView
                    android:id="@+id/mobile_signal_voice"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    />
            </LinearLayout>
        </FrameLayout>
    </LinearLayout>
    
    

    二、状态栏信号显示流程

    接下来是信号的显示流程,android 8.0开始,与之前的android版本信号显示不太一样了。8.0源生代码中信号图标都是代码画出来的,并非与之前版本一样,直接使用图片显示了。所以,在开发中,我需要自己去修改,定制自己的信号样式,显示规格。
    SignalClusterView.java
    路径:frameworks\base\package\SystemUI\src\com\android\systemui\statusbar\SignalClusterView.java。它对应布局signal_cluster_view.xml,刚刚上面介绍过。
    SignalClusterView.java完成控件的初始化、赋予图片显示。
    下面,来说说它的逻辑。
    SignalClusterView.java中有个内部类:PhoneState。
    PhoneState中的apply()方法中对信号控件进行赋值。
    其中mMobile就是信号控件
    如下代码。

     public boolean apply(boolean isSecondaryIcon) {
                if (mMobileVisible && !mIsAirplaneMode) {
                    if (mLastMobileStrengthId != mMobileStrengthId) {
                        if (mReadIconsFromXML) {
                           setIconForView(mMobile, mMobileStrengthId);
                            setIconForView(mMobileDark, mMobileStrengthId);
    
                        } else {
                            mMobile.getDrawable().setLevel(mMobileStrengthId);
                            mMobileDark.getDrawable().setLevel(mMobileStrengthId);
                        }
                        mLastMobileStrengthId = mMobileStrengthId;
                    }
    
                    if (mLastMobileTypeId != mMobileTypeId) {
                        mMobileType.setImageResource(mMobileTypeId);
                        mLastMobileTypeId = mMobileTypeId;
                    }
    
                    mDataActivity.setImageResource(mDataActivityId);
    
                    if (mStackedDataId != 0 && mStackedVoiceId != 0) {
                        mStackedData.setImageResource(mStackedDataId);
                        mStackedVoice.setImageResource(mStackedVoiceId);
                        mMobileSingleGroup.setVisibility(View.GONE);
                        mMobileStackedGroup.setVisibility(View.VISIBLE);
                    } else {
                        mStackedData.setImageResource(0);
                        mStackedVoice.setImageResource(0);
                        mMobileSingleGroup.setVisibility(View.VISIBLE);
                        mMobileStackedGroup.setVisibility(View.GONE);
                    }
    
                    mMobileGroup.setContentDescription(mMobileTypeDescription
                            + " " + mMobileDescription);
                    mMobileGroup.setVisibility(View.VISIBLE);
                } else {
                    mMobileGroup.setVisibility(View.GONE);
                }
    
                // 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 (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
                            (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
    
                mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
                mMobileRoaming.setVisibility((mRoaming && !mReadIconsFromXML)? View.VISIBLE : View.GONE);
                mMobileActivityIn.setVisibility(mActivityIn ? View.VISIBLE : View.GONE);
                mMobileActivityOut.setVisibility(mActivityOut ? View.VISIBLE : View.GONE);
                mDataActivity.setVisibility(mDataActivityId != 0 ? View.VISIBLE : View.GONE);
    
                return mMobileVisible;
            }
    

    ~
    mReadIconsFromXML:是定义在config.xml中config_read_icons_from_xml的值,顾名思义。
    setIconForView:设置图片,mIconScaleFactor是定义在dimen.xml中的值:status_bar_icon_scale_factor;

    下面是setIconForView

     private void setIconForView(ImageView imageView, @DrawableRes int iconId) {
            // Using the imageView's context to retrieve the Drawable so that theme is preserved.
            Drawable icon = imageView.getContext().getDrawable(iconId);
    
            if (mIconScaleFactor == 1.f) {
                imageView.setImageDrawable(icon);
            } else {
                imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));
            }
        }
    

    ~
    ~
    下面主要来说说:setIconForView(mMobile, mMobileStrengthId);中的mMobileStrengthId,这个特别重要。在MobileSignalController.java中的方法notifyListeners()中调用SignalClusterView.javasetMobileDataIndicators()方法传进来的。
    下面是setMobileDataIndicators()

       @Override
        public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
                int qsType, boolean activityIn, boolean activityOut, int dataActivityId,
                int stackedDataId, int stackedVoiceId,String typeContentDescription,
                String description, boolean isWide, int subId, boolean roaming) {
            PhoneState state = getState(subId);
            if (state == null) {
                return;
            }
    
            state.mMobileVisible = statusIcon.visible && !mBlockMobile;
            #state.mMobileStrengthId = statusIcon.icon;
            state.mMobileTypeId = statusType;
            state.mMobileDescription = statusIcon.contentDescription;
            state.mMobileTypeDescription = typeContentDescription;
            state.mIsMobileTypeIconWide = statusType != 0 && isWide;
            state.mRoaming = roaming;
            state.mActivityIn = activityIn && mActivityEnabled && !mWifiVisible;
            state.mActivityOut = activityOut && mActivityEnabled && !mWifiVisible;
            state.mDataActivityId = dataActivityId;
            state.mStackedDataId = stackedDataId;
            state.mStackedVoiceId = stackedVoiceId;
    
            apply();
        }
    
    

    ~
    ~
    MobileSignalController.java中的方法notifyListeners()

     @Override
        public void notifyListeners(SignalCallback callback) {
            if (mConfig.readIconsFromXml) {
                generateIconGroup();
            }
            MobileIconGroup icons = getIcons();
    
            String contentDescription = getStringIfExists(getContentDescription());
            String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
            final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
                    && mCurrentState.userSetup;
    
            // Show icon in QS when we are connected or data is disabled.
            boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
            IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
                    getCurrentIconId(), contentDescription);
    
            int qsTypeIcon = 0;
            IconState qsIcon = null;
            String description = null;
            // Only send data sim callbacks to QS.
            if (mCurrentState.dataSim) {
                qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
                qsIcon = new IconState(mCurrentState.enabled
                        && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
                description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
            }
            boolean activityIn = mCurrentState.dataConnected
                    && !mCurrentState.carrierNetworkChangeMode
                    && mCurrentState.activityIn;
            boolean activityOut = mCurrentState.dataConnected
                    && !mCurrentState.carrierNetworkChangeMode
                    && mCurrentState.activityOut;
            showDataIcon &= mCurrentState.isDefault || dataDisabled;
            if (SystemProperties.getBoolean("persist.vendor.radio.L_L_4G", false)
                    && (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA
                           || mDataNetType == TelephonyManager.NETWORK_TYPE_LTE)) showDataIcon = true;
            int typeIcon = (showDataIcon && mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT) ? icons.mDataType : 0;
            int dataActivityId = showDataIcon && !showMobileActivity() ? icons.mActivityId : 0;
            callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                    activityIn, activityOut, dataActivityId,
                    icons.mStackedDataIcon, icons.mStackedVoiceIcon,
                    dataContentDescription, description, icons.mIsWide,
                    mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
        }
    
    

    ~
    statusIcon:见setMobileDataIndicators()蓝色部分代码。
    statusIcon.icon对应下面代码getCurrentIconId()。不明白可以看下面NetworkController.java。

     IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
                    getCurrentIconId(), contentDescription);
    

    NetworkController.java中的内部类IconState
    路径:\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\NetworkController.java

     public static class IconState {
            public final boolean visible;
            public final int icon;
            public final String contentDescription;
    
            public IconState(boolean visible, int icon, String contentDescription) {
                this.visible = visible;
                this.icon = icon;
                this.contentDescription = contentDescription;
            }
    
            public IconState(boolean visible, int icon, int contentDescription,
                    Context context) {
                this(visible, icon, context.getString(contentDescription));
            }
        }
    

    android8.0和以前版本的区别就在这里。getCurrentIconId():

    下面是8.0的代码,在8.0中是直接通过信号级别然后通过SignalDrawable代码绘制图片完成的。先对来说比往常版本要简单,但是如果要使用自己的信号样式,就是说定制信号样式。那么可以根据往常的版本来做。

     @Override
        public int getCurrentIconId() {
            if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
                return SignalDrawable.getCarrierChangeState(getNumLevels());
            } else if (mCurrentState.connected) {
                int level = mCurrentState.level;
                if (mConfig.inflateSignalStrengths) {
                    level++;
                }
                if (mConfig.readIconsFromXml) {
                    return getIcons().mSingleSignalIcon;
                } else {
                    return SignalDrawable.getState(level, getNumLevels(),
                        false);
                }
            } else if (mCurrentState.enabled) {
                if (mConfig.readIconsFromXml) {
                    return getIcons().mSbDiscState;
                } else {
                    return SignalDrawable.getEmptyState(getNumLevels());
                }
            } else {
                return 0;
            }
        }
    

    ~
    ~
    ~
    以下是8.0之前的处理情况,直接获取信号级别图片,而这个图片呢是在你的res资源文件中。下面细看。
    如果你要定制信号,请将readIconsFromXml 设置为true或改写代码。
    readIconsFromXml 之前介绍过,在config中有定义。

     @Override
        public int getCurrentIconId() {
             if (mConfig.readIconsFromXml && mCurrentState.connected) {
                return getIcons().mSingleSignalIcon;
            } else {
                return super.getCurrentIconId();
            }
        }
    
    

    情况一、没有改写readIconsFromXml 。
    return super.getCurrentIconId();
    父类\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policySignalController.java中的getCurrentIconId()和getIcons();

      public int getCurrentIconId() {
            if (mCurrentState.connected) {
                return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level];
            } else if (mCurrentState.enabled) {
                return getIcons().mSbDiscState;
            } else {
                return getIcons().mSbNullState;
            }
        }
    
     protected I getIcons() {
            return (I) mCurrentState.iconGroup;
        }
    
    

    这里有点小复杂,MobileSignalController.java继承了SignalController.java。
    并在generateIconGroup()对mCurrentState.iconGroup进行了赋值。
    sbIcons 后面那个null是qsIcons,源生代码上状态栏下拉数据开关是显示信号的,一般看到手机上的都是开发者修改后的。
    这里sbIcons使用了TelephonyIcons中的一个数组,数组中对应res中的信号图片文件。

           int[][] sbIcons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
     mCurrentState.iconGroup = new MobileIconGroup(
                    TelephonyManager.getNetworkTypeName(dataType),
                    sbIcons , null, contentDesc, 0, 0, sbDiscState, 0, discContentDesc,
                    dataContentDesc, dataTypeIcon, false, qsDataTypeIcon,
                    singleSignalIcon, stackedDataIcon, stackedVoiceIcon, dataActivityId);
    

    ~~以上这种情况是简单的定制。但是比较复杂一点的定制这样就无法完成,比如三星的部分手机,还有个品牌手机电信卡信号显示双层信号。
    ~~
    ~~

    下面说说第二种情况。

     @Override
        public int getCurrentIconId() {
             if (mConfig.readIconsFromXml && mCurrentState.connected) {
                return getIcons().mSingleSignalIcon;
            } else {
                return super.getCurrentIconId();
            }
        }
    
    

    当修改过mConfig.readIconsFromXml的值。
    return getIcons().mSingleSignalIcon;
    mSingleSignalIcon:对应上方代码
    mCurrentState.iconGroup = new MobileIconGroup(.........){........}

    中的参数singleSignalIcon。
    而singleSignalIcon是通过generateIconGroup()方法从TelephonyIcons中获取的。(generateIconGroup详情,请看源码MobileSignalController.java)

    singleSignalIcon = TelephonyIcons.getSignalStrengthIcon(slotId, inet, level, roaming);
    

    ~
    ~

    下面介绍一下TelephonyIcons.java

    getSignalStrengthIcon():返回值就是根据传进参数获取的信号级别图片。

    mSignalStrengthArray:

    获取的是res中array.xml中的三维数组,数组中存放着图片名称。R.array.multi_signal_strength

      readIconsFromXml()方法中:
       mSignalStrengthArray = mRes.getStringArray(R.array.multi_signal_strength);
    
     static int getSignalStrengthIcon(int slot, int inet, int level, boolean roaming) {
            log(TAG, "getSignalStrengthIcon: " + String.format(
                    "slot=%d, inetCondition=%d, level=%d, roaming=%b", slot, inet, level, roaming));
    
            String[] signalStrengthArray, selectedTypeArray;
    
            signalStrengthArray = mRes.getStringArray(mRes.getIdentifier(!roaming ?
                    mSignalStrengthArray[slot] : mSignalStrengthRoamingArray[slot], null, NS));
            log(TAG, String.format("signalStrengthArray.length=%d", signalStrengthArray.length));
    
            selectedTypeArray = mRes.getStringArray(mRes.getIdentifier(
                    signalStrengthArray[mSelectedSignalStreagthIndex[slot]], null, NS));
            log(TAG, String.format("selectedTypeArray.length=%d", selectedTypeArray.length));
    
            String[] inetArray = mRes.getStringArray(
                    mRes.getIdentifier(selectedTypeArray[inet], null, NS));
            log(TAG, String.format("inetArray.length=%d", inetArray.length));
    
            return mRes.getIdentifier(inetArray[level], null, NS);
        }
    

    ~
    这里在说一下,如果定制自己的信号样式的时候。发现代码修改都没有问题,R.array.multi_signal_strength的修改也没有问题。咦,怎么显示的和我在R.array.multi_signal_strength写的图片不一样,这个时候,检查一下android\vendor\qcom\proprietary\qrdplus\China下面。有三个文件夹ChinaMobile、ChinaTelecom、ChinaUnicom。一般是默认使用ChinaTelecom。为什么看这里呢,因为如果这里的array.xml的R.array.multi_signal_strength中和SystemUI中的R.array.multi_signal_strength中有相同的数组名字,它会使用ChinaTelecom中array.xml中的值。有点绕,希望能看明白。
    ~
    ~
    ~

    信号定制、信号显示流程就到这里,能看懂的其实数据流量图标显示样式也能这样修改。下次有时间再写写信号是如何上报的,WIFI开启流程等等。欢迎读者交流,相互成长。

    相关文章

      网友评论

          本文标题:Android 8.0 状态栏信号显示、信号定制

          本文链接:https://www.haomeiwen.com/subject/khmpuftx.html