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

您所在的位置:网站首页 安卓状态栏修改5g图标显示 Android 8.0 状态栏信号显示、信号定制

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

2023-09-09 00:12| 来源: 网络整理| 查看: 265

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

一、状态栏信号布局

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

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

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

~

mobile_signal_group.xml 二、状态栏信号显示流程

接下来是信号的显示流程,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.java中setMobileDataIndicators()方法传进来的。 下面是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开启流程等等。欢迎读者交流,相互成长。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3