Google CellBroadcast

it2024-07-02  39

一、背景

Android R及以上版本,必须集成Google Cellbroadcast。 CellBroadcast模块由两部分组成:

CellBroadcastService 此服务支持CellBroadcast SMS解码,无线紧急警报(WEA)3.0的地理围栏,消息重复检查以及向应用程序广播消息。CellBroadcastReceiver: 默认系统应用程序,用于处理紧急/非紧急警报,并根据运营商和区域法规向最终用户显示信息。

CellBroadcastService和CellBroadcastReceiver应用程序包含在单个APEX文件(com.google.android.cellbroadcast)中,OEMs无法修改。但是OEMs可以使用runtime resource overlays覆盖(RRO)自定义配置。 在Android R中,CellBroadcast模块在package/app/CellBroadcastReceiver中包含代码,并将现有框架类迁移到package/modules/CellBroadcastService。也就是说,可以在这两个部分查看代码,修改无效。

二、模块介绍

小区广播(CB)是一对多的地理定位和地理防御消息服务,旨在将消息同时发送到定义区域中的多个移动电话用户。 当警报信息到来,设备会立即弹出警报框:

三、CellBroadcast消息流程

1)无线电接口层(RIL)向InBoundSMSHandler通知CDMA / GSM CellBroadcast SMS。 2)framework将CellBroadcast SMS转发到CBS模块,以解析和处理传入的消息。 3)处理完消息后,CellBroadcastService会将intent转发到系统默认的CellBroadcastReceiver应用程序。 4)CellBroadcastReceiver应用程序将消息显示给用户。

四、CellBroadcast RRO

OEMs无法直接修改源码,但是可以参考RROSampleTestApp使用runtime resource overlays覆盖(RRO)自定义配置(仅overlayable.xml文件中定义的)。 注意事项:必须设置targetPackage为“com.google.android.cellbroadcastreceiver”

五、CellBroadcast Settings解析

<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <Preference android:key="alerts_header" android:summary="@string/alerts_header_summary" android:selectable="false" /> <!-- Allow alerts --> <SwitchPreference android:defaultValue="@bool/master_toggle_enabled_default" android:key="enable_alerts_master_toggle" android:summary="@string/enable_alerts_master_toggle_summary" android:title="@string/enable_alerts_master_toggle_title" /> <!--Alerts --> <PreferenceCategory android:title="@string/emergency_alerts_title" android:key="category_emergency_alerts"> <!-- Emergency alerts --> <SwitchPreference android:defaultValue="@bool/emergency_alerts_enabled_default" android:key="enable_emergency_alerts" android:summary="@string/enable_emergency_alerts_message_summary" android:title="@string/enable_emergency_alerts_message_title" /> <!-- Presidential alerts --> <SwitchPreference android:defaultValue="true" android:enabled="false" android:key="enable_cmas_presidential_alerts" android:summary="@string/enable_cmas_presidential_alerts_summary" android:title="@string/enable_cmas_presidential_alerts_title"/> <!-- Extreme threats --> <SwitchPreference android:defaultValue="@bool/extreme_threat_alerts_enabled_default" android:key="enable_cmas_extreme_threat_alerts" android:summary="@string/enable_cmas_extreme_threat_alerts_summary" android:title="@string/enable_cmas_extreme_threat_alerts_title" /> <!-- Severe threats --> <SwitchPreference android:defaultValue="@bool/severe_threat_alerts_enabled_default" android:key="enable_cmas_severe_threat_alerts" android:summary="@string/enable_cmas_severe_threat_alerts_summary" android:title="@string/enable_cmas_severe_threat_alerts_title" /> <!-- AMBER alerts --> <SwitchPreference android:defaultValue="@bool/amber_alerts_enabled_default" android:key="enable_cmas_amber_alerts" android:summary="@string/enable_cmas_amber_alerts_summary" android:title="@string/enable_cmas_amber_alerts_title" /> <!-- Public safety messages --> <SwitchPreference android:defaultValue="@bool/public_safety_messages_enabled_default" android:key="enable_public_safety_messages" android:summary="@string/enable_public_safety_messages_summary" android:title="@string/enable_public_safety_messages_title" /> <!-- State and local tests --> <SwitchPreference android:defaultValue="@bool/state_local_test_alerts_enabled_default" android:key="enable_state_local_test_alerts" android:summary="@string/enable_state_local_test_alerts_summary" android:title="@string/enable_state_local_test_alerts_title" /> <!-- Test alerts --> <SwitchPreference android:defaultValue="@bool/test_alerts_enabled_default" android:key="enable_test_alerts" android:summary="@string/enable_cmas_test_alerts_summary" android:title="@string/enable_cmas_test_alerts_title" /> <!-- Area update broadcasts --> <!-- Default value is true for Brazil and India. This preference is ignored and hidden unless the boolean "config_showAreaUpdateInfoSettings" is set to true in the global resource. --> <SwitchPreference android:defaultValue="@bool/area_update_info_alerts_enabled_default" android:key="enable_area_update_info_alerts" android:summary="@string/enable_area_update_info_alerts_summary" android:title="@string/enable_area_update_info_alerts_title" /> <!-- Emergency alert history --> <Preference android:key="emergency_alert_history" android:title="@string/emergency_alert_history_title" /> </PreferenceCategory> <!-- Alert preferences --> <PreferenceCategory android:title="@string/alert_preferences_title" android:key="category_alert_preferences"> <!-- Vibration --> <SwitchPreference android:defaultValue="true" android:key="enable_alert_vibrate" android:title="@string/enable_alert_vibrate_title" /> <!-- Alert reminder --> <ListPreference android:key="alert_reminder_interval" android:title="@string/alert_reminder_interval_title" android:entries="@array/alert_reminder_interval_entries" android:entryValues="@array/alert_reminder_interval_values" android:defaultValue="@string/alert_reminder_interval_in_min_default" android:dialogTitle="@string/alert_reminder_dialog_title" /> <!-- Show additional language on/off switch in settings --> <SwitchPreference android:defaultValue="false" android:key="receive_cmas_in_second_language" android:summary="@string/receive_cmas_in_second_language_summary" android:title="@string/receive_cmas_in_second_language_title" /> <!-- Always alert at full volume --> <SwitchPreference android:defaultValue="@bool/override_dnd_default" android:key="override_dnd" android:summary="@string/override_dnd_summary" android:title="@string/override_dnd_title" /> </PreferenceCategory> </PreferenceScreen>

1、Allow alerts

<SwitchPreference android:defaultValue="@bool/master_toggle_enabled_default" android:key="enable_alerts_master_toggle" android:summary="@string/enable_alerts_master_toggle_summary" android:title="@string/enable_alerts_master_toggle_title" />

用于启用/禁用所有警报消息(默认启用,仅对Presidential alerts无效) 该控件无法隐藏

2、Presidential alerts

<SwitchPreference android:defaultValue="true" android:enabled="false" android:key="enable_cmas_presidential_alerts" android:summary="@string/enable_cmas_presidential_alerts_summary" android:title="@string/enable_cmas_presidential_alerts_title"/>

默认开启该channel但该控件隐藏。 OEM可在RRO中配置show_presidential_alerts_settings,设置是否显示该控件。

if (mPresidentialCheckBox != null) { mPresidentialCheckBox.setVisible( res.getBoolean(R.bool.show_presidential_alerts_settings)); }

默认控制channel为:gsm(4370, 4383)和cdma(4096)

3、Extreme threats

<SwitchPreference android:defaultValue="@bool/extreme_threat_alerts_enabled_default" android:key="enable_cmas_extreme_threat_alerts" android:summary="@string/enable_cmas_extreme_threat_alerts_summary" android:title="@string/enable_cmas_extreme_threat_alerts_title" />

默认开启该channel。 该控件在show_extreme_alert_settings为true且cmas_alert_extreme_channels_range_strings不为null的情况下才显示。

if (mExtremeCheckBox != null) { mExtremeCheckBox.setVisible(res.getBoolean(R.bool.show_extreme_alert_settings) && !channelManager.getCellBroadcastChannelRanges( R.array.cmas_alert_extreme_channels_range_strings).isEmpty()); }

默认show_extreme_alert_settings为true。 默认控制channel为:gsm(4371~4372, 4384~4385)和cdma(4097)

4、Severe threats

<SwitchPreference android:defaultValue="@bool/severe_threat_alerts_enabled_default" android:key="enable_cmas_severe_threat_alerts" android:summary="@string/enable_cmas_severe_threat_alerts_summary" android:title="@string/enable_cmas_severe_threat_alerts_title" />

默认开启该channel。 该控件在show_severe_alert_settings为true且cmas_alerts_severe_range_strings不为null的情况下才显示。

if (mSevereCheckBox != null) { mSevereCheckBox.setVisible(res.getBoolean(R.bool.show_severe_alert_settings) && !channelManager.getCellBroadcastChannelRanges( R.array.cmas_alerts_severe_range_strings).isEmpty()); }

默认show_severe_alert_settings为true。 默认控制channel为:gsm(4373~4378, 4386~4391)和cdma(4098)

5、AMBER alerts

<SwitchPreference android:defaultValue="@bool/amber_alerts_enabled_default" android:key="enable_cmas_amber_alerts" android:summary="@string/enable_cmas_amber_alerts_summary" android:title="@string/enable_cmas_amber_alerts_title" />

默认开启该channel。 该控件在show_amber_alert_settings为true且cmas_amber_alerts_channels_range_strings不为null的情况下才显示。

if (mAmberCheckBox != null) { mAmberCheckBox.setVisible(res.getBoolean(R.bool.show_amber_alert_settings) && !channelManager.getCellBroadcastChannelRanges( R.array.cmas_amber_alerts_channels_range_strings).isEmpty()); }

默认show_amber_alert_settings为true。 默认控制channel为:gsm(4379, 4392)和cdma(4099)

6、Public safety messages

<SwitchPreference android:defaultValue="@bool/public_safety_messages_enabled_default" android:key="enable_public_safety_messages" android:summary="@string/enable_public_safety_messages_summary" android:title="@string/enable_public_safety_messages_title" />

默认开启该channel。 该控件在show_public_safety_settings为true且public_safety_messages_channels_range_strings不为null的情况下才显示。

if (mPublicSafetyMessagesChannelCheckBox != null) { mPublicSafetyMessagesChannelCheckBox.setVisible( res.getBoolean(R.bool.show_public_safety_settings) && !channelManager.getCellBroadcastChannelRanges( R.array.public_safety_messages_channels_range_strings) .isEmpty()); }

默认show_public_safety_settings为true。 默认控制channel为null。 MCCMNC不同,public_safety_messages_channels_range_strings值不同。mcc310的情况下,控制channel为:gsm(4096, 4097)

7、State and local tests

<SwitchPreference android:defaultValue="@bool/state_local_test_alerts_enabled_default" android:key="enable_state_local_test_alerts" android:summary="@string/enable_state_local_test_alerts_summary" android:title="@string/enable_state_local_test_alerts_title" />

默认不开启该channel。 该控件在show_state_local_test_settings为true且state_local_test_alert_range_strings不为null的情况下才显示。

if (mStateLocalTestCheckBox != null) { mStateLocalTestCheckBox.setVisible( res.getBoolean(R.bool.show_state_local_test_settings) && !channelManager.getCellBroadcastChannelRanges( R.array.state_local_test_alert_range_strings).isEmpty()); }

默认show_state_local_test_settings为true。 默认控制channel为null。 MCCMNC不同,state_local_test_alert_range_strings值不同。mcc310的情况下,控制channel为:gsm(4098, 4099)

8、Test alerts

<SwitchPreference android:defaultValue="@bool/test_alerts_enabled_default" android:key="enable_test_alerts" android:summary="@string/enable_cmas_test_alerts_summary" android:title="@string/enable_cmas_test_alerts_title" />

默认不开启该channel。 该控件是否显示由isTestAlertsToggleVisible(Context context)控制。

if (mTestCheckBox != null) { mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext())); }

当(show_test_settings为true或isTestingMode(context))且(required_monthly_test_range_strings或exercise_alert_range_strings或operator_defined_alert_range_strings或etws_test_alerts_range_strings不为null)时显示。

public static boolean isTestAlertsToggleVisible(Context context) { CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); Resources res = CellBroadcastSettings.getResources(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges( R.array.required_monthly_test_range_strings).isEmpty() || !channelManager.getCellBroadcastChannelRanges( R.array.exercise_alert_range_strings).isEmpty() || !channelManager.getCellBroadcastChannelRanges( R.array.operator_defined_alert_range_strings).isEmpty() || !channelManager.getCellBroadcastChannelRanges( R.array.etws_test_alerts_range_strings).isEmpty(); return (res.getBoolean(R.bool.show_test_settings) || CellBroadcastReceiver.isTestingMode(context)) && isTestAlertsAvailable; }

默认show_test_settings为true 默认required_monthly_test_range_strings控制channel为:gsm(4380, 4393)和cdma(4100) 默认exercise_alert_range_strings控制channel为:gsm(4381, 4394) 默认operator_defined_alert_range_strings控制channel为:gsm(4382, 4395) 默认etws_test_alerts_range_strings控制channel为:gsm(4352~4354, 4356) isTestingMode(context)取决于SECRET_CODE

”ro.debuggable“为1即root版本或者allow_testing_mode_on_user_build为true时,可通过暗码”##CMAS##“启动。

else if (TelephonyManager.ACTION_SECRET_CODE.equals(action)) { if (SystemProperties.getInt("ro.debuggable", 0) == 1 || res.getBoolean(R.bool.allow_testing_mode_on_user_build)) { setTestingMode(!isTestingMode(mContext)); int msgId = (isTestingMode(mContext)) ? R.string.testing_mode_enabled : R.string.testing_mode_disabled; String msg = res.getString(msgId); Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); LocalBroadcastManager.getInstance(mContext) .sendBroadcast(new Intent(ACTION_TESTING_MODE_CHANGED)); log(msg); } }

发送了一个本地广播

LocalBroadcastManager.getInstance(mContext) .sendBroadcast(new Intent(ACTION_TESTING_MODE_CHANGED));

广播接收

private final BroadcastReceiver mTestingModeChangedReeiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED: updatePreferenceVisibility(); break; } } };

该控件是否显示还是由isTestAlertsToggleVisible(Context context)控制。

private void updatePreferenceVisibility() { ...... if (mTestCheckBox != null) { mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext())); } ...... }

例如: 插入卡MCCMNC为310260,且不为root版本时。 直接从Settings菜单看,show_test_settings为false,则再看isTestingMode(context)。可看到allow_testing_mode_on_user_build为true,isTestAlertsAvailable为true,则isTestAlertsToggleVisible(Context context)返回true,即该控件存在。 从暗码中看,虽不为root版本,但allow_testing_mode_on_user_build为true,固可通过暗码启动。

六、关于语言过滤

private boolean shouldDisplayMessage(SmsCbMessage message) { ...... // Check if we need to perform language filtering. CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(mContext, message.getSubscriptionId()); CellBroadcastChannelRange range = channelManager .getCellBroadcastChannelRangeFromMessage(message); String messageLanguage = message.getLanguageCode(); if (range != null && range.mFilterLanguage) { // language filtering based on CBR second language settings final String secondLanguageCode = CellBroadcastSettings.getResources(mContext, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) .getString(R.string.emergency_alert_second_language_code); if (!secondLanguageCode.isEmpty()) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); boolean receiveInSecondLanguage = prefs.getBoolean( CellBroadcastSettings.KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE, false); // For DCS values that bit 6 is 1 and bit 7 is 0, language field is not defined so // ap receives it as null value and so alert is not shown to the user. // bypass language filter in this case. if (!TextUtils.isEmpty(messageLanguage) && !secondLanguageCode.equalsIgnoreCase(messageLanguage)) { Log.w(TAG, "Ignoring message in the unspecified second language:" + messageLanguage); return false; } else if (!receiveInSecondLanguage) { Log.d(TAG, "Ignoring message in second language because setting is off"); return false; } } else { // language filtering based on device language settings. String deviceLanguage = Locale.getDefault().getLanguage(); // Apply If the message's language does not match device's message, we don't // display the message. if (!TextUtils.isEmpty(messageLanguage) && !messageLanguage.equalsIgnoreCase(deviceLanguage)) { Log.d(TAG, "ignoring the alert due to language mismatch. Message lang=" + messageLanguage + ", device lang=" + deviceLanguage); return false; } } } ...... return true; }

range != null && range.mFilterLanguage才会进入语言过滤。 range.mFilterLanguage看如下中filter_language的值,默认false。

<item>0x111F:rat=gsm, emergency=true, filter_language=true</item>

七、其他

1、添加启动icon

google有提供以下两个参数,用于通过其自己的启动icon来访问CellBroadcast消息历史记录。

<item type="bool" name="show_message_history_in_launcher" /> <item type="mipmap" name="ic_launcher_cell_broadcast" />

使用如下:

<?xml version="1.0" encoding="utf-8"?> <resources> <bool name="show_message_history_in_launcher">true</bool> <mipmap name="ic_launcher_cell_broadcast">@mipmap/ic_launcher_cell_broadcast</mipmap> </resources>
最新回复(0)