Support config for roaming network
Bug: 198618350
Test: atest CellBroadcastReceiverUnitTests
Test: manual
Change-Id: I1d666c1a3260328d1e3cf4eca3f3ac1a70af2bd9
Merged-Id: I1d666c1a3260328d1e3cf4eca3f3ac1a70af2bd9
diff --git a/Android.bp b/Android.bp
index 43bd173..4e45773 100644
--- a/Android.bp
+++ b/Android.bp
@@ -40,6 +40,7 @@
"SettingsLibSettingsTheme",
"SettingsLibCollapsingToolbarBaseActivity",
"SettingsLibMainSwitchPreference",
+ "SettingsLibTopIntroPreference",
"modules-utils-build_system",
],
optimize: {
diff --git a/res/values/config.xml b/res/values/config.xml
index 9c2c0c2..ffc722a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -181,6 +181,15 @@
<!-- Channels to receive geo-fencing trigger messages -->
<string-array name="geo_fencing_trigger_messages_range_strings" translatable="false"></string-array>
+ <!-- List of roaming network operator to be supported.
+ The item can be operator numeric as 3 digits of mcc, 6 or 5 digits of mcc+mnc, or special
+ characters as XXX to match any mcc, XXXXXX to match any mcc+mnc. If multiple items match
+ the roaming network, only the first one will take effect. -->
+ <string-array name="cmas_roaming_network_strings" translatable="false">
+ <!-- France -->
+ <item>208</item>
+ </string-array>
+
<!-- Values that are retrieved from the ListPreference.
These must match the alert_reminder_interval_entries list above. -->
<string-array name="alert_reminder_interval_values" translatable="false">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 77fae22..7c140dc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -384,6 +384,11 @@
<!-- Emergency alert message copied to clipboard. -->
<string name="message_copied">Message copied</string>
+ <!-- The top introduction to show by default. -->
+ <string name="top_intro_default_text"></string>
+ <!-- The top introduction to show for roaming network support. -->
+ <string name="top_intro_roaming_text">While you\'re roaming, you may get some alerts that aren\'t included in these settings</string>
+
<!-- Notification title and text when alerting user that their CB settings have changed -->
<string name="notification_cb_settings_changed_title">Settings changed by carrier</string>
<string name="notification_cb_settings_changed_text">Tap to see wireless emergency alert settings</string>
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 327e902..fc0649e 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -25,6 +25,9 @@
android:icon="@drawable/ic_info_outline_24dp"
android:selectable="false" />
+ <com.android.settingslib.widget.TopIntroPreference
+ android:key="alert_prefs_top_intro"/>
+
<com.android.settingslib.widget.MainSwitchPreference android:defaultValue="@bool/master_toggle_enabled_default"
android:key="enable_alerts_master_toggle"
android:summary="@string/enable_alerts_master_toggle_summary"
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
index c57faa4..a479d7a 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertDialog.java
@@ -715,7 +715,9 @@
Context context = getApplicationContext();
int titleId = CellBroadcastResources.getDialogTitleResource(context, message);
- Resources res = CellBroadcastSettings.getResources(context, message.getSubscriptionId());
+ Resources res = CellBroadcastSettings.getResourcesByOperator(context,
+ message.getSubscriptionId(),
+ CellBroadcastReceiver.getRoamingOperatorSupported(context));
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
this, message.getSubscriptionId());
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
index b5edce2..85e6293 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
@@ -57,6 +57,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -206,8 +207,8 @@
CellBroadcastChannelManager channelManager =
new CellBroadcastChannelManager(mContext, message.getSubscriptionId());
// check the full-screen message settings to hide or show message to users.
- if (channelManager.checkCellBroadcastChannelRange(message.getServiceCategory(),
- R.array.public_safety_messages_channels_range_strings)) {
+ if (channelManager.getCellBroadcastChannelResourcesKey(message.getServiceCategory())
+ == R.array.public_safety_messages_channels_range_strings) {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN,
true);
@@ -455,35 +456,36 @@
* @return true if the channel is enabled on the device, otherwise false.
*/
private boolean isChannelEnabled(SmsCbMessage message) {
- CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(mContext,
- message.getSubscriptionId());
+ int subId = message.getSubscriptionId();
+ CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
+ mContext, subId);
CellBroadcastChannelRange chanelrange = channelManager
.getCellBroadcastChannelRangeFromMessage(message);
- Resources res = CellBroadcastSettings.getResources(mContext, message.getSubscriptionId());
+ Resources res = CellBroadcastSettings.getResourcesByOperator(mContext, subId,
+ CellBroadcastReceiver.getRoamingOperatorSupported(this));
if (chanelrange != null && chanelrange.mAlwaysOn) {
Log.d(TAG, "channel is enabled due to always-on, ignoring preference check");
return true;
}
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// Check if all emergency alerts are disabled.
- boolean emergencyAlertEnabled =
- prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true);
+ boolean emergencyAlertEnabled = checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true);
int channel = message.getServiceCategory();
+ int resourcesKey = channelManager.getCellBroadcastChannelResourcesKey(channel);
+ CellBroadcastChannelRange range = channelManager.getCellBroadcastChannelRange(channel);
SmsCbEtwsInfo etwsInfo = message.getEtwsWarningInfo();
if ((etwsInfo != null && etwsInfo.getWarningType()
== SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE)
- || channelManager.checkCellBroadcastChannelRange(channel,
- R.array.etws_test_alerts_range_strings)) {
+ || resourcesKey == R.array.etws_test_alerts_range_strings) {
return emergencyAlertEnabled
&& CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext())
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
+ && checkAlertConfigEnabled(subId,
+ CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
}
- if (message.isEtwsMessage() || channelManager.checkCellBroadcastChannelRange(channel,
- R.array.etws_alerts_range_strings)) {
+ if (message.isEtwsMessage() || resourcesKey == R.array.etws_alerts_range_strings) {
// ETWS messages.
// Turn on/off emergency notifications is the only way to turn on/off ETWS messages.
return emergencyAlertEnabled;
@@ -492,109 +494,79 @@
// Check if the messages are on additional channels enabled by the resource config.
// If those channels are enabled by the carrier, but the device is actually roaming, we
// should not allow the messages.
- ArrayList<CellBroadcastChannelRange> ranges = channelManager.getCellBroadcastChannelRanges(
- R.array.additional_cbs_channels_strings);
-
- for (CellBroadcastChannelRange range : ranges) {
- if (range.mStartId <= channel && range.mEndId >= channel) {
- // Check if the channel is within the scope. If not, ignore the alert message.
- if (!channelManager.checkScope(range.mScope)) {
- Log.d(TAG, "The range [" + range.mStartId + "-" + range.mEndId
- + "] is not within the scope. mScope = " + range.mScope);
- return false;
- }
-
- if (range.mAlertType == AlertType.TEST) {
- return emergencyAlertEnabled
- && CellBroadcastSettings.isTestAlertsToggleVisible(
- getApplicationContext())
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS,
- false);
- }
- if (range.mAlertType == AlertType.AREA) {
- return emergencyAlertEnabled && PreferenceManager
- .getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS,
- false);
- }
-
- return emergencyAlertEnabled;
+ if (resourcesKey == R.array.additional_cbs_channels_strings) {
+ // Check if the channel is within the scope. If not, ignore the alert message.
+ if (!channelManager.checkScope(range.mScope)) {
+ Log.d(TAG, "The range [" + range.mStartId + "-" + range.mEndId
+ + "] is not within the scope. mScope = " + range.mScope);
+ return false;
}
+
+ if (range.mAlertType == AlertType.TEST) {
+ return emergencyAlertEnabled
+ && CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext())
+ && checkAlertConfigEnabled(subId,
+ CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
+ }
+ if (range.mAlertType == AlertType.AREA) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(subId,
+ CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS, false);
+ }
+
+ return emergencyAlertEnabled;
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.emergency_alerts_channels_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
- CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
+ if (resourcesKey == R.array.emergency_alerts_channels_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
}
// CMAS warning types
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.cmas_presidential_alerts_channels_range_strings)) {
+ if (resourcesKey == R.array.cmas_presidential_alerts_channels_range_strings) {
// always enabled
return true;
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.cmas_alert_extreme_channels_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
- CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true);
+ if (resourcesKey == R.array.cmas_alert_extreme_channels_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true);
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.cmas_alerts_severe_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
- CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true);
+ if (resourcesKey == R.array.cmas_alerts_severe_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true);
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.cmas_amber_alerts_channels_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true);
+ if (resourcesKey == R.array.cmas_amber_alerts_channels_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true);
}
- if (channelManager.checkCellBroadcastChannelRange(
- channel, R.array.exercise_alert_range_strings) &&
- res.getBoolean(R.bool.show_separate_exercise_settings)) {
- return emergencyAlertEnabled && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_EXERCISE_ALERTS, false);
+ if (resourcesKey == R.array.exercise_alert_range_strings
+ && res.getBoolean(R.bool.show_separate_exercise_settings)) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_EXERCISE_ALERTS, false);
}
- if (channelManager.checkCellBroadcastChannelRange(
- channel, R.array.operator_defined_alert_range_strings) &&
- res.getBoolean(R.bool.show_separate_operator_defined_settings)) {
- return emergencyAlertEnabled && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_OPERATOR_DEFINED_ALERTS, false);
+ if (resourcesKey == R.array.operator_defined_alert_range_strings
+ && res.getBoolean(R.bool.show_separate_operator_defined_settings)) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_OPERATOR_DEFINED_ALERTS, false);
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.required_monthly_test_range_strings)
- || channelManager.checkCellBroadcastChannelRange(channel,
- R.array.exercise_alert_range_strings)
- || channelManager.checkCellBroadcastChannelRange(channel,
- R.array.operator_defined_alert_range_strings)) {
+ if (resourcesKey == R.array.required_monthly_test_range_strings
+ || resourcesKey == R.array.exercise_alert_range_strings
+ || resourcesKey == R.array.operator_defined_alert_range_strings) {
return emergencyAlertEnabled
&& CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext())
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS,
- false);
+ && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.public_safety_messages_channels_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES,
- true);
+ if (resourcesKey == R.array.public_safety_messages_channels_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES, true);
}
- if (channelManager.checkCellBroadcastChannelRange(channel,
- R.array.state_local_test_alert_range_strings)) {
- return emergencyAlertEnabled
- && PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS,
- false);
+ if (resourcesKey == R.array.state_local_test_alert_range_strings) {
+ return emergencyAlertEnabled && checkAlertConfigEnabled(
+ subId, CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS, false);
}
Log.e(TAG, "received undefined channels: " + channel);
@@ -648,7 +620,7 @@
}
} else {
int channel = message.getServiceCategory();
- ArrayList<CellBroadcastChannelRange> ranges = channelManager
+ List<CellBroadcastChannelRange> ranges = channelManager
.getAllCellBroadcastChannelRanges();
for (CellBroadcastChannelRange range : ranges) {
if (channel >= range.mStartId && channel <= range.mEndId) {
@@ -996,4 +968,23 @@
}
return false;
}
+
+ private boolean checkAlertConfigEnabled(int subId, String key, boolean defaultValue) {
+ boolean result = defaultValue;
+ String roamingOperator = CellBroadcastReceiver.getRoamingOperatorSupported(this);
+ // For roaming supported case
+ if (!roamingOperator.isEmpty()) {
+ int resId = CellBroadcastSettings.getResourcesIdForDefaultPrefValue(key);
+ if (resId != 0) {
+ result = CellBroadcastSettings.getResourcesByOperator(
+ mContext, subId, roamingOperator).getBoolean(resId);
+ // For roaming support case, the channel can be enabled by the default config
+ // for the network even it is disabled by the preference
+ if (result) {
+ return true;
+ }
+ }
+ }
+ return PreferenceManager.getDefaultSharedPreferences(this).getBoolean(key, defaultValue);
+ }
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastChannelManager.java b/src/com/android/cellbroadcastreceiver/CellBroadcastChannelManager.java
index a56cd0a..22ececa 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastChannelManager.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastChannelManager.java
@@ -18,15 +18,22 @@
import static android.telephony.ServiceState.ROAMING_TYPE_NOT_ROAMING;
+import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.VDBG;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.os.SystemProperties;
import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SmsCbMessage;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
import androidx.annotation.VisibleForTesting;
@@ -35,6 +42,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* CellBroadcastChannelManager handles the additional cell broadcast channels that
@@ -54,6 +62,7 @@
private static final String TAG = "CBChannelManager";
+ private static final int MAX_CACHE_SIZE = 3;
private static List<Integer> sCellBroadcastRangeResourceKeys = new ArrayList<>(
Arrays.asList(R.array.additional_cbs_channels_strings,
R.array.emergency_alerts_channels_range_strings,
@@ -70,13 +79,19 @@
R.array.state_local_test_alert_range_strings
));
- private static ArrayList<CellBroadcastChannelRange> sAllCellBroadcastChannelRanges = null;
- private static final Object channelRangesLock = new Object();
+ private static Map<Integer, Map<Integer, List<CellBroadcastChannelRange>>>
+ sAllCellBroadcastChannelRangesPerSub = new ArrayMap<>();
+ private static Map<String, Map<Integer, List<CellBroadcastChannelRange>>>
+ sAllCellBroadcastChannelRangesPerOperator = new ArrayMap<>();
+
+ private static final Object mChannelRangesLock = new Object();
private final Context mContext;
private final int mSubId;
+ private final String mOperator;
+
private boolean mIsDebugBuild = false;
/**
@@ -167,14 +182,14 @@
// Display both ways dialog and notification
public boolean mDisplayDialogWithNotification = false;
- public CellBroadcastChannelRange(Context context, int subId, String channelRange) {
+ public CellBroadcastChannelRange(Context context, int subId,
+ Resources res, String channelRange) {
mAlertType = AlertType.DEFAULT;
mEmergencyLevel = LEVEL_UNKNOWN;
mRanType = SmsCbMessage.MESSAGE_FORMAT_3GPP;
mScope = SCOPE_UNKNOWN;
- mVibrationPattern =
- CellBroadcastSettings.getResources(context, subId)
- .getIntArray(R.array.default_vibration_pattern);
+
+ mVibrationPattern = res.getIntArray(R.array.default_vibration_pattern);
mFilterLanguage = false;
// by default all received messages should be displayed.
mDisplay = true;
@@ -293,8 +308,7 @@
// If alert type is info, override vibration pattern
if (!hasVibrationPattern && mAlertType.equals(AlertType.INFO)) {
- mVibrationPattern = CellBroadcastSettings.getResources(context, subId)
- .getIntArray(R.array.default_notification_vibration_pattern);
+ mVibrationPattern = res.getIntArray(R.array.default_notification_vibration_pattern);
}
// Parse the channel range
@@ -331,14 +345,88 @@
* @param subId Subscription index
*/
public CellBroadcastChannelManager(Context context, int subId) {
- this(context, subId, SystemProperties.getInt("ro.debuggable", 0) == 1);
+ this(context, subId, CellBroadcastReceiver.getRoamingOperatorSupported(context),
+ SystemProperties.getInt("ro.debuggable", 0) == 1);
+ }
+
+ public CellBroadcastChannelManager(Context context, int subId, @Nullable String operator) {
+ this(context, subId, operator, SystemProperties.getInt("ro.debuggable", 0) == 1);
}
@VisibleForTesting
- public CellBroadcastChannelManager(Context context, int subId, boolean isDebugBuild) {
+ public CellBroadcastChannelManager(Context context, int subId,
+ String operator, boolean isDebugBuild) {
mContext = context;
mSubId = subId;
+ mOperator = operator;
mIsDebugBuild = isDebugBuild;
+ initAsNeeded();
+ }
+
+ /**
+ * Parse channel ranges from resources, and initialize the cache as needed
+ */
+ private void initAsNeeded() {
+ if (!TextUtils.isEmpty(mOperator)) {
+ synchronized (mChannelRangesLock) {
+ if (!sAllCellBroadcastChannelRangesPerOperator.containsKey(mOperator)) {
+ if (VDBG) {
+ log("init for operator: " + mOperator);
+ }
+ if (sAllCellBroadcastChannelRangesPerOperator.size() == MAX_CACHE_SIZE) {
+ sAllCellBroadcastChannelRangesPerOperator.clear();
+ }
+ sAllCellBroadcastChannelRangesPerOperator.put(mOperator,
+ getChannelRangesMapFromResoures(CellBroadcastSettings
+ .getResourcesByOperator(mContext, mSubId, mOperator)));
+ }
+ }
+ }
+
+ synchronized (mChannelRangesLock) {
+ if (!sAllCellBroadcastChannelRangesPerSub.containsKey(mSubId)) {
+ if (sAllCellBroadcastChannelRangesPerSub.size() == MAX_CACHE_SIZE) {
+ sAllCellBroadcastChannelRangesPerSub.clear();
+ }
+ if (VDBG) {
+ log("init for sub: " + mSubId);
+ }
+ sAllCellBroadcastChannelRangesPerSub.put(mSubId,
+ getChannelRangesMapFromResoures(CellBroadcastSettings
+ .getResources(mContext, mSubId)));
+ }
+ }
+ }
+
+ private @NonNull Map<Integer, List<CellBroadcastChannelRange>> getChannelRangesMapFromResoures(
+ @NonNull Resources res) {
+ Map<Integer, List<CellBroadcastChannelRange>> map = new ArrayMap<>();
+
+ for (int key : sCellBroadcastRangeResourceKeys) {
+ String[] ranges = res.getStringArray(key);
+ if (ranges != null) {
+ List<CellBroadcastChannelRange> rangesList = new ArrayList<>();
+ for (String range : ranges) {
+ try {
+ if (VDBG) {
+ log("parse channel range: " + range);
+ }
+ CellBroadcastChannelRange r =
+ new CellBroadcastChannelRange(mContext, mSubId, res, range);
+ // Bypass if the range is disabled
+ if (r.mIsDebugBuildOnly && !mIsDebugBuild) {
+ continue;
+ }
+ rangesList.add(r);
+ } catch (Exception e) {
+ loge("Failed to parse \"" + range + "\". e=" + e);
+ }
+ }
+ map.put(key, rangesList);
+ }
+ }
+
+ return map;
}
/**
@@ -348,26 +436,23 @@
*
* @return The list of channel ranges enabled by the carriers.
*/
- public @NonNull ArrayList<CellBroadcastChannelRange> getCellBroadcastChannelRanges(int key) {
- ArrayList<CellBroadcastChannelRange> result = new ArrayList<>();
- String[] ranges =
- CellBroadcastSettings.getResources(mContext, mSubId).getStringArray(key);
- if (ranges != null) {
- for (String range : ranges) {
- try {
- CellBroadcastChannelRange r =
- new CellBroadcastChannelRange(mContext, mSubId, range);
- // Bypass if the range is disabled
- if (r.mIsDebugBuildOnly && !mIsDebugBuild) {
- continue;
- }
- result.add(r);
- } catch (Exception e) {
- loge("Failed to parse \"" + range + "\". e=" + e);
- }
+ public @NonNull List<CellBroadcastChannelRange> getCellBroadcastChannelRanges(int key) {
+ List<CellBroadcastChannelRange> result = null;
+
+ synchronized (mChannelRangesLock) {
+ initAsNeeded();
+
+ // Check the config per network first if applicable
+ if (!TextUtils.isEmpty(mOperator)) {
+ result = sAllCellBroadcastChannelRangesPerOperator.get(mOperator).get(key);
+ }
+
+ if (result == null) {
+ result = sAllCellBroadcastChannelRangesPerSub.get(mSubId).get(key);
}
}
- return result;
+
+ return result == null ? new ArrayList<>() : result;
}
/**
@@ -375,31 +460,28 @@
*
* @return all cell broadcast channels
*/
- public @NonNull ArrayList<CellBroadcastChannelRange> getAllCellBroadcastChannelRanges() {
- synchronized(channelRangesLock) {
- if (sAllCellBroadcastChannelRanges != null) return sAllCellBroadcastChannelRanges;
-
- Log.d(TAG, "Create new channel range list");
- ArrayList<CellBroadcastChannelRange> result = new ArrayList<>();
-
- for (int key : sCellBroadcastRangeResourceKeys) {
- result.addAll(getCellBroadcastChannelRanges(key));
+ public @NonNull List<CellBroadcastChannelRange> getAllCellBroadcastChannelRanges() {
+ final List<CellBroadcastChannelRange> result = new ArrayList<>();
+ synchronized (mChannelRangesLock) {
+ if (!TextUtils.isEmpty(mOperator)
+ && sAllCellBroadcastChannelRangesPerOperator.containsKey(mOperator)) {
+ sAllCellBroadcastChannelRangesPerOperator.get(mOperator).forEach(
+ (k, v)->result.addAll(v));
}
- sAllCellBroadcastChannelRanges = result;
- return result;
+ sAllCellBroadcastChannelRangesPerSub.get(mSubId).forEach((k, v)->result.addAll(v));
}
+ return result;
}
/**
* Clear broadcast channel range list
*/
public static void clearAllCellBroadcastChannelRanges() {
- synchronized(channelRangesLock) {
- if (sAllCellBroadcastChannelRanges != null) {
- Log.d(TAG, "Clear channel range list");
- sAllCellBroadcastChannelRanges = null;
- }
+ synchronized (mChannelRangesLock) {
+ Log.d(TAG, "Clear channel range list");
+ sAllCellBroadcastChannelRangesPerSub.clear();
+ sAllCellBroadcastChannelRangesPerOperator.clear();
}
}
@@ -411,15 +493,59 @@
* return {@code FALSE} otherwise
*/
public boolean checkCellBroadcastChannelRange(int channel, int key) {
- ArrayList<CellBroadcastChannelRange> ranges = getCellBroadcastChannelRanges(key);
+ return getCellBroadcastChannelResourcesKey(channel) == key;
+ }
- for (CellBroadcastChannelRange range : ranges) {
- if (channel >= range.mStartId && channel <= range.mEndId) {
- return checkScope(range.mScope);
+ /**
+ * Get the resources key for the channel
+ * @param channel Cell broadcast message channel
+ *
+ * @return 0 if the key is not found, otherwise the value of the resources key
+ */
+ public int getCellBroadcastChannelResourcesKey(int channel) {
+ Pair<Integer, CellBroadcastChannelRange> p = findChannelRange(channel);
+
+ return p != null ? p.first : 0;
+ }
+
+ /**
+ * Get the CellBroadcastChannelRange for the channel
+ * @param channel Cell broadcast message channel
+ *
+ * @return the CellBroadcastChannelRange for the channel, null if not found
+ */
+ public @Nullable CellBroadcastChannelRange getCellBroadcastChannelRange(int channel) {
+ Pair<Integer, CellBroadcastChannelRange> p = findChannelRange(channel);
+
+ return p != null ? p.second : null;
+ }
+
+ private @Nullable Pair<Integer, CellBroadcastChannelRange> findChannelRange(int channel) {
+ if (!TextUtils.isEmpty(mOperator)) {
+ Pair<Integer, CellBroadcastChannelRange> p = findChannelRange(
+ sAllCellBroadcastChannelRangesPerOperator.get(mOperator), channel);
+ if (p != null) {
+ return p;
}
}
- return false;
+ return findChannelRange(sAllCellBroadcastChannelRangesPerSub.get(mSubId), channel);
+ }
+
+ private @Nullable Pair<Integer, CellBroadcastChannelRange> findChannelRange(
+ Map<Integer, List<CellBroadcastChannelRange>> channelRangeMap, int channel) {
+ if (channelRangeMap != null) {
+ for (Map.Entry<Integer, List<CellBroadcastChannelRange>> entry
+ : channelRangeMap.entrySet()) {
+ for (CellBroadcastChannelRange range : entry.getValue()) {
+ if (channel >= range.mStartId && channel <= range.mEndId
+ && checkScope(range.mScope)) {
+ return new Pair<>(entry.getKey(), range);
+ }
+ }
+ }
+ }
+ return null;
}
/**
@@ -474,24 +600,7 @@
+ message.getSubscriptionId());
}
- int channel = message.getServiceCategory();
- ArrayList<CellBroadcastChannelRange> ranges = null;
-
- for (int key : sCellBroadcastRangeResourceKeys) {
- if (checkCellBroadcastChannelRange(channel, key)) {
- ranges = getCellBroadcastChannelRanges(key);
- break;
- }
- }
- if (ranges != null) {
- for (CellBroadcastChannelRange range : ranges) {
- if (range.mStartId <= message.getServiceCategory()
- && range.mEndId >= message.getServiceCategory()) {
- return range;
- }
- }
- }
- return null;
+ return getCellBroadcastChannelRange(message.getServiceCategory());
}
/**
@@ -511,25 +620,19 @@
}
int id = message.getServiceCategory();
+ CellBroadcastChannelRange range = getCellBroadcastChannelRange(id);
- for (int key : sCellBroadcastRangeResourceKeys) {
- ArrayList<CellBroadcastChannelRange> ranges =
- getCellBroadcastChannelRanges(key);
- for (CellBroadcastChannelRange range : ranges) {
- if (range.mStartId <= id && range.mEndId >= id) {
- switch (range.mEmergencyLevel) {
- case CellBroadcastChannelRange.LEVEL_EMERGENCY:
- Log.d(TAG, "isEmergencyMessage: true, message id = " + id);
- return true;
- case CellBroadcastChannelRange.LEVEL_NOT_EMERGENCY:
- Log.d(TAG, "isEmergencyMessage: false, message id = " + id);
- return false;
- case CellBroadcastChannelRange.LEVEL_UNKNOWN:
- default:
- break;
- }
+ if (range != null) {
+ switch (range.mEmergencyLevel) {
+ case CellBroadcastChannelRange.LEVEL_EMERGENCY:
+ Log.d(TAG, "isEmergencyMessage: true, message id = " + id);
+ return true;
+ case CellBroadcastChannelRange.LEVEL_NOT_EMERGENCY:
+ Log.d(TAG, "isEmergencyMessage: false, message id = " + id);
+ return false;
+ case CellBroadcastChannelRange.LEVEL_UNKNOWN:
+ default:
break;
- }
}
}
@@ -541,6 +644,10 @@
return message.isEmergencyMessage();
}
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
private static void loge(String msg) {
Log.e(TAG, msg);
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
index 9b9b75a..d00eef8 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
@@ -30,6 +30,7 @@
import android.telephony.SmsManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -81,10 +82,13 @@
for (int subId : subIds) {
log("Enable CellBroadcast on sub " + subId);
enableCellBroadcastChannels(subId);
+ enableCellBroadcastRoamingChannelsAsNeeded(subId);
}
} else {
// For no sim scenario.
enableCellBroadcastChannels(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+ enableCellBroadcastRoamingChannelsAsNeeded(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
}
}
} catch (Exception ex) {
@@ -164,7 +168,7 @@
resetCellBroadcastChannels(subId);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- Resources res = CellBroadcastSettings.getResources(this, subId);
+ Resources res = getResources(subId, null);
// boolean for each user preference checkbox, true for checked, false for unchecked
// Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts
@@ -215,14 +219,29 @@
boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
- boolean enableGeoFencingTriggerMessage = true;
+ setCellBroadcastChannelsEnabled(subId, null, enableAlertsMasterToggle, enableEtwsAlerts,
+ enablePresidential, enableCmasExtremeAlerts, enableCmasSevereAlerts,
+ enableCmasAmberAlerts, enableTestAlerts, enableExerciseAlerts,
+ enableOperatorDefined, enableAreaUpdateInfoAlerts,
+ enablePublicSafetyMessagesChannelAlerts, enableStateLocalTestAlerts,
+ enableEmergencyAlerts, true);
+ }
+
+ private void setCellBroadcastChannelsEnabled(int subId, @NonNull String operator,
+ boolean enableAlertsMasterToggle, boolean enableEtwsAlerts, boolean enablePresidential,
+ boolean enableCmasExtremeAlerts, boolean enableCmasSevereAlerts,
+ boolean enableCmasAmberAlerts, boolean enableTestAlerts, boolean enableExerciseAlerts,
+ boolean enableOperatorDefined, boolean enableAreaUpdateInfoAlerts,
+ boolean enablePublicSafetyMessagesChannelAlerts, boolean enableStateLocalTestAlerts,
+ boolean enableEmergencyAlerts, boolean enableGeoFencingTriggerMessage) {
if (VDBG) {
+ log("setCellBroadcastChannelsEnabled for " + subId + ", operator: " + operator);
log("enableAlertsMasterToggle = " + enableAlertsMasterToggle);
log("enableEtwsAlerts = " + enableEtwsAlerts);
log("enablePresidential = " + enablePresidential);
log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts);
- log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts);
+ log("enableCmasSevereAlerts = " + enableCmasSevereAlerts);
log("enableCmasAmberAlerts = " + enableCmasAmberAlerts);
log("enableTestAlerts = " + enableTestAlerts);
log("enableExerciseAlerts = " + enableExerciseAlerts);
@@ -235,80 +254,81 @@
log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage);
}
+ boolean isEnableOnly = !TextUtils.isEmpty(operator);
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
- getApplicationContext(), subId);
+ getApplicationContext(), subId, operator);
/** Enable CMAS series messages. */
// Enable/Disable Presidential messages.
- setCellBroadcastRange(subId, enablePresidential,
+ setCellBroadcastRange(subId, isEnableOnly, enablePresidential,
channelManager.getCellBroadcastChannelRanges(
R.array.cmas_presidential_alerts_channels_range_strings));
// Enable/Disable CMAS extreme messages.
- setCellBroadcastRange(subId, enableCmasExtremeAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableCmasExtremeAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.cmas_alert_extreme_channels_range_strings));
// Enable/Disable CMAS severe messages.
- setCellBroadcastRange(subId, enableCmasSevereAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableCmasSevereAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.cmas_alerts_severe_range_strings));
// Enable/Disable CMAS amber alert messages.
- setCellBroadcastRange(subId, enableCmasAmberAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableCmasAmberAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.cmas_amber_alerts_channels_range_strings));
// Enable/Disable test messages.
- setCellBroadcastRange(subId, enableTestAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.required_monthly_test_range_strings));
// Enable/Disable exercise test messages.
// This could either controlled by main test toggle or separate exercise test toggle.
- setCellBroadcastRange(subId, enableTestAlerts || enableExerciseAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts || enableExerciseAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.exercise_alert_range_strings));
// Enable/Disable operator defined test messages.
// This could either controlled by main test toggle or separate operator defined test toggle
- setCellBroadcastRange(subId, enableTestAlerts || enableOperatorDefined,
+ setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts || enableOperatorDefined,
channelManager.getCellBroadcastChannelRanges(
R.array.operator_defined_alert_range_strings));
// Enable/Disable GSM ETWS messages.
- setCellBroadcastRange(subId, enableEtwsAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableEtwsAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.etws_alerts_range_strings));
// Enable/Disable GSM ETWS test messages.
- setCellBroadcastRange(subId, enableTestAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.etws_test_alerts_range_strings));
// Enable/Disable GSM public safety messages.
- setCellBroadcastRange(subId, enablePublicSafetyMessagesChannelAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enablePublicSafetyMessagesChannelAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.public_safety_messages_channels_range_strings));
// Enable/Disable GSM state/local test alerts.
- setCellBroadcastRange(subId, enableStateLocalTestAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableStateLocalTestAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.state_local_test_alert_range_strings));
// Enable/Disable GSM geo-fencing trigger messages.
- setCellBroadcastRange(subId, enableGeoFencingTriggerMessage,
+ setCellBroadcastRange(subId, isEnableOnly, enableGeoFencingTriggerMessage,
channelManager.getCellBroadcastChannelRanges(
R.array.geo_fencing_trigger_messages_range_strings));
// Enable non-CMAS series messages.
- setCellBroadcastRange(subId, enableEmergencyAlerts,
+ setCellBroadcastRange(subId, isEnableOnly, enableEmergencyAlerts,
channelManager.getCellBroadcastChannelRanges(
R.array.emergency_alerts_channels_range_strings));
// Enable/Disable additional channels based on carrier specific requirement.
- ArrayList<CellBroadcastChannelRange> ranges =
+ List<CellBroadcastChannelRange> ranges =
channelManager.getCellBroadcastChannelRanges(
R.array.additional_cbs_channels_strings);
@@ -324,17 +344,88 @@
default:
enableAlerts = enableAlertsMasterToggle;
}
- setCellBroadcastRange(subId, enableAlerts, new ArrayList<>(Arrays.asList(range)));
+ setCellBroadcastRange(subId, isEnableOnly, enableAlerts,
+ new ArrayList<>(Arrays.asList(range)));
}
}
+
+ /**
+ * Enable cell broadcast messages channels. Messages can be only received on the
+ * enabled channels.
+ *
+ * @param subId Subscription index
+ */
+ @VisibleForTesting
+ public void enableCellBroadcastRoamingChannelsAsNeeded(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ }
+
+ String roamingOperator = CellBroadcastReceiver.getRoamingOperatorSupported(this);
+ if (roamingOperator.isEmpty()) {
+ return;
+ }
+
+ log("enableCellBroadcastRoamingChannels for roaming network:" + roamingOperator);
+ Resources res = getResources(subId, roamingOperator);
+
+ // Get default config for roaming network as the settings are based on sim
+ boolean enablePresidential = true;
+
+ boolean enableAlertsMasterToggle = res.getBoolean(R.bool.master_toggle_enabled_default);
+
+ boolean enableEtwsAlerts = enableAlertsMasterToggle;
+
+ boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && res.getBoolean(
+ R.bool.extreme_threat_alerts_enabled_default);
+
+ boolean enableCmasSevereAlerts = enableAlertsMasterToggle && res.getBoolean(
+ R.bool.severe_threat_alerts_enabled_default);
+
+ boolean enableCmasAmberAlerts = enableAlertsMasterToggle && res.getBoolean(
+ R.bool.amber_alerts_enabled_default);
+
+ boolean enableTestAlerts = enableAlertsMasterToggle && CellBroadcastSettings
+ .isTestAlertsToggleVisible(getApplicationContext(), roamingOperator)
+ && res.getBoolean(R.bool.test_alerts_enabled_default);
+
+ boolean enableExerciseAlerts = enableAlertsMasterToggle
+ && res.getBoolean(R.bool.show_separate_exercise_settings)
+ && res.getBoolean(R.bool.test_exercise_alerts_enabled_default);
+
+ boolean enableOperatorDefined = enableAlertsMasterToggle
+ && res.getBoolean(R.bool.show_separate_operator_defined_settings)
+ && res.getBoolean(R.bool.test_operator_defined_alerts_enabled_default);
+
+ boolean enableAreaUpdateInfoAlerts = res.getBoolean(
+ R.bool.config_showAreaUpdateInfoSettings)
+ && res.getBoolean(R.bool.area_update_info_alerts_enabled_default);
+
+ boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle
+ && res.getBoolean(R.bool.public_safety_messages_enabled_default);
+ boolean enableStateLocalTestAlerts = enableAlertsMasterToggle
+ && res.getBoolean(R.bool.state_local_test_alerts_enabled_default);
+
+ boolean enableEmergencyAlerts = enableAlertsMasterToggle && res.getBoolean(
+ R.bool.emergency_alerts_enabled_default);
+
+ setCellBroadcastChannelsEnabled(subId, roamingOperator, enableAlertsMasterToggle,
+ enableEtwsAlerts, enablePresidential, enableCmasExtremeAlerts,
+ enableCmasSevereAlerts, enableCmasAmberAlerts, enableTestAlerts,
+ enableExerciseAlerts, enableOperatorDefined, enableAreaUpdateInfoAlerts,
+ enablePublicSafetyMessagesChannelAlerts, enableStateLocalTestAlerts,
+ enableEmergencyAlerts, true);
+ }
+
/**
* Enable/disable cell broadcast with messages id range
* @param subId Subscription index
- * @param enable True for enabling cell broadcast with id range, otherwise for disabling.
+ * @param isEnableOnly, True for enabling channel only for roaming network
+ * @param enable True for enabling cell broadcast with id range, otherwise for disabling
* @param ranges Cell broadcast id ranges
*/
- private void setCellBroadcastRange(int subId, boolean enable,
- List<CellBroadcastChannelRange> ranges) {
+ private void setCellBroadcastRange(int subId, boolean isEnableOnly,
+ boolean enable, List<CellBroadcastChannelRange> ranges) {
SmsManager manager;
if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
manager = SmsManager.getSmsManagerForSubscriptionId(subId);
@@ -349,15 +440,39 @@
+ ":" + range.mEndId);
enable = true;
}
+
if (enable) {
+ if (VDBG) {
+ log("enableCellBroadcastRange[" + range.mStartId + "-" + range.mEndId
+ + "], type:" + range.mRanType);
+ }
manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType);
- } else {
+ } else if (!isEnableOnly) {
+ if (VDBG) {
+ log("disableCellBroadcastRange[" + range.mStartId + "-" + range.mEndId
+ + "], type:" + range.mRanType);
+ }
manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType);
}
}
}
}
+
+ /**
+ * Get resource according to the operator or subId
+ * @param subId Subscription index
+ * @param operator Operator numeric, the resource will be retrieved by it if it is no null,
+ * otherwise, by the sub id.
+ */
+ @VisibleForTesting
+ public Resources getResources(int subId, String operator) {
+ if (operator == null) {
+ return CellBroadcastSettings.getResources(this, subId);
+ }
+ return CellBroadcastSettings.getResourcesByOperator(this, subId, operator);
+ }
+
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
index 0a4cf07..ae45c0e 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
@@ -32,7 +32,6 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserManager;
-import androidx.preference.PreferenceManager;
import android.provider.Telephony;
import android.provider.Telephony.CellBroadcasts;
import android.telephony.CarrierConfigManager;
@@ -46,12 +45,13 @@
import android.widget.Toast;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.preference.PreferenceManager;
import com.android.cellbroadcastservice.CellBroadcastStatsLog;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
-
+import java.util.Arrays;
public class CellBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "CellBroadcastReceiver";
@@ -69,6 +69,9 @@
// Key to access the shared preference of service state.
private static final String SERVICE_STATE = "service_state";
+ // Key to access the shared preference of roaming operator.
+ private static final String ROAMING_OPERATOR_SUPPORTED = "roaming_operator_supported";
+
// shared preference under developer settings
private static final String ENABLE_ALERT_MASTER_PREF = "enable_alerts_master_toggle";
@@ -94,6 +97,11 @@
public static final String ACTION_TESTING_MODE_CHANGED =
"com.android.cellbroadcastreceiver.intent.ACTION_TESTING_MODE_CHANGED";
+ // System property to set roaming network config which can be multiple items split by
+ // comma, and matched in sequence. This config will insert before the overlay.
+ private static final String ROAMING_PLMN_SUPPORTED_PROPERTY_KEY =
+ "persist.cellbroadcast.roaming_plmn_supported";
+
private Context mContext;
/**
@@ -146,11 +154,7 @@
// configurations once moving back from APM. This should be fixed in lower layer
// going forward.
int ss = intent.getIntExtra(EXTRA_VOICE_REG_STATE, ServiceState.STATE_IN_SERVICE);
- if (ss != ServiceState.STATE_POWER_OFF
- && getServiceState(context) == ServiceState.STATE_POWER_OFF) {
- startConfigServiceToEnableChannels();
- }
- setServiceState(ss);
+ onServiceStateChanged(context, res, ss);
} else if (CELLBROADCAST_START_CONFIG_ACTION.equals(action)
|| SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED.equals(action)) {
startConfigServiceToEnableChannels();
@@ -202,6 +206,61 @@
}
}
+ private void onServiceStateChanged(Context context, Resources res, int ss) {
+ logd("onServiceStateChanged, ss: " + ss);
+ // check whether to support roaming network
+ String roamingOperator = null;
+ if (ss == ServiceState.STATE_IN_SERVICE || ss == ServiceState.STATE_EMERGENCY_ONLY) {
+ TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ String networkOperator = tm.getNetworkOperator();
+ logd("networkOperator: " + networkOperator);
+
+ // check roaming config only if the network oprator is not empty as the config
+ // is based on operator numeric
+ if (!networkOperator.isEmpty()) {
+ // No roaming supported by default
+ roamingOperator = "";
+ if ((tm.isNetworkRoaming() || ss == ServiceState.STATE_EMERGENCY_ONLY)
+ && !networkOperator.equals(tm.getSimOperator())) {
+ String propRoamingPlmn = SystemProperties.get(
+ ROAMING_PLMN_SUPPORTED_PROPERTY_KEY, "").trim();
+ String[] roamingNetworks = propRoamingPlmn.isEmpty() ? res.getStringArray(
+ R.array.cmas_roaming_network_strings) : propRoamingPlmn.split(",");
+ logd("roamingNetworks: " + Arrays.toString(roamingNetworks));
+
+ for (String r : roamingNetworks) {
+ r = r.trim();
+ if (r.equals("XXXXXX")) {
+ //match any roaming network, store mcc+mnc
+ roamingOperator = networkOperator;
+ break;
+ } else if (r.equals("XXX")) {
+ //match any roaming network, only store mcc
+ roamingOperator = networkOperator.substring(0, 3);
+ break;
+ } else if (networkOperator.startsWith(r)) {
+ roamingOperator = r;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ((ss != ServiceState.STATE_POWER_OFF
+ && getServiceState(context) == ServiceState.STATE_POWER_OFF)
+ || (roamingOperator != null && !roamingOperator.equals(
+ getRoamingOperatorSupported(context)))) {
+ startConfigServiceToEnableChannels();
+ }
+ setServiceState(ss);
+
+ if (roamingOperator != null) {
+ log("update supported roaming operator as " + roamingOperator);
+ setRoamingOperatorSupported(roamingOperator);
+ }
+ }
+
/**
* Send an intent to reset the users WEA settings if there is a new carrier on the default subId
*
@@ -276,7 +335,7 @@
.apply();
}
- /**
+ /**
* Enable/disable cell broadcast receiver testing mode.
*
* @param on {@code true} if testing mode is on, otherwise off.
@@ -307,6 +366,14 @@
}
/**
+ * Store the roaming operator
+ */
+ private void setRoamingOperatorSupported(String roamingOperator) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+ sp.edit().putString(ROAMING_OPERATOR_SUPPORTED, roamingOperator).commit();
+ }
+
+ /**
* @return the stored voice registration service state
*/
private static int getServiceState(Context context) {
@@ -315,6 +382,14 @@
}
/**
+ * @return the supported roaming operator
+ */
+ public static String getRoamingOperatorSupported(Context context) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ return sp.getString(ROAMING_OPERATOR_SUPPORTED, "");
+ }
+
+ /**
* update reminder interval
*/
@VisibleForTesting
@@ -624,6 +699,10 @@
Log.d(TAG, msg);
}
+ private static void logd(String msg) {
+ if (DBG) Log.d(TAG, msg);
+ }
+
private static void loge(String msg) {
Log.e(TAG, msg);
}
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java b/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
index 35d418d..16bbb69 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastResources.java
@@ -31,7 +31,6 @@
import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange;
import java.text.DateFormat;
-import java.util.ArrayList;
import java.util.Locale;
/**
@@ -313,18 +312,15 @@
context, message.getSubscriptionId());
final int serviceCategory = message.getServiceCategory();
// store to different SMS threads based on channel mappings.
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.cmas_presidential_alerts_channels_range_strings)) {
- return R.string.sms_cb_sender_name_presidential;
+ switch (channelManager.getCellBroadcastChannelResourcesKey(serviceCategory)) {
+ case R.array.cmas_presidential_alerts_channels_range_strings:
+ return R.string.sms_cb_sender_name_presidential;
+ case R.array.emergency_alerts_channels_range_strings:
+ return R.string.sms_cb_sender_name_emergency;
+ case R.array.public_safety_messages_channels_range_strings:
+ return R.string.sms_cb_sender_name_public_safety;
}
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.emergency_alerts_channels_range_strings)) {
- return R.string.sms_cb_sender_name_emergency;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.public_safety_messages_channels_range_strings)) {
- return R.string.sms_cb_sender_name_public_safety;
- }
+
return R.string.sms_cb_sender_name_default;
}
@@ -356,82 +352,60 @@
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
context, subId);
final int serviceCategory = message.getServiceCategory();
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.emergency_alerts_channels_range_strings)) {
- return R.string.pws_other_message_identifiers;
- }
- // CMAS warning types
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.cmas_presidential_alerts_channels_range_strings)) {
- return R.string.cmas_presidential_level_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.cmas_alert_extreme_channels_range_strings)) {
- if (message.isCmasMessage()) {
- if (cmasInfo.getSeverity() == SmsCbCmasInfo.CMAS_SEVERITY_EXTREME
- && cmasInfo.getUrgency() == SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE) {
- if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED) {
- return R.string.cmas_extreme_immediate_observed_alert;
- } else if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY) {
- return R.string.cmas_extreme_immediate_likely_alert;
- }
- }
- }
- return R.string.cmas_extreme_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.cmas_alerts_severe_range_strings)) {
- return R.string.cmas_severe_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.cmas_amber_alerts_channels_range_strings)) {
- return R.string.cmas_amber_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.required_monthly_test_range_strings)) {
- return R.string.cmas_required_monthly_test;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.exercise_alert_range_strings)) {
- return R.string.cmas_exercise_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.operator_defined_alert_range_strings)) {
- return R.string.cmas_operator_defined_alert;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.public_safety_messages_channels_range_strings)) {
- return R.string.public_safety_message;
- }
- if (channelManager.checkCellBroadcastChannelRange(serviceCategory,
- R.array.state_local_test_alert_range_strings)) {
- return R.string.state_local_test_alert;
- }
+ int resourcesKey = channelManager.getCellBroadcastChannelResourcesKey(serviceCategory);
+ CellBroadcastChannelRange range = channelManager
+ .getCellBroadcastChannelRange(serviceCategory);
- if (channelManager.isEmergencyMessage(message)) {
- ArrayList<CellBroadcastChannelRange> ranges =
- channelManager.getCellBroadcastChannelRanges(
- R.array.additional_cbs_channels_strings);
- if (ranges != null) {
- for (CellBroadcastChannelRange range : ranges) {
- if (serviceCategory >= range.mStartId && serviceCategory <= range.mEndId) {
- // Apply the closest title to the specified tones.
- switch (range.mAlertType) {
- case DEFAULT:
- return R.string.pws_other_message_identifiers;
- case ETWS_EARTHQUAKE:
- return R.string.etws_earthquake_warning;
- case ETWS_TSUNAMI:
- return R.string.etws_tsunami_warning;
- case TEST:
- return R.string.etws_test_message;
- case ETWS_DEFAULT:
- case OTHER:
- return R.string.etws_other_emergency_type;
+ switch (resourcesKey) {
+ case R.array.emergency_alerts_channels_range_strings:
+ return R.string.pws_other_message_identifiers;
+ case R.array.cmas_presidential_alerts_channels_range_strings:
+ return R.string.cmas_presidential_level_alert;
+ case R.array.cmas_alert_extreme_channels_range_strings:
+ if (message.isCmasMessage()) {
+ if (cmasInfo.getSeverity() == SmsCbCmasInfo.CMAS_SEVERITY_EXTREME
+ && cmasInfo.getUrgency() == SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE) {
+ if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED) {
+ return R.string.cmas_extreme_immediate_observed_alert;
+ } else if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY) {
+ return R.string.cmas_extreme_immediate_likely_alert;
}
}
}
+ return R.string.cmas_extreme_alert;
+ case R.array.cmas_alerts_severe_range_strings:
+ return R.string.cmas_severe_alert;
+ case R.array.cmas_amber_alerts_channels_range_strings:
+ return R.string.cmas_amber_alert;
+ case R.array.required_monthly_test_range_strings:
+ return R.string.cmas_required_monthly_test;
+ case R.array.exercise_alert_range_strings:
+ return R.string.cmas_exercise_alert;
+ case R.array.operator_defined_alert_range_strings:
+ return R.string.cmas_operator_defined_alert;
+ case R.array.public_safety_messages_channels_range_strings:
+ return R.string.public_safety_message;
+ case R.array.state_local_test_alert_range_strings:
+ return R.string.state_local_test_alert;
+ }
+ if (channelManager.isEmergencyMessage(message)) {
+ if (resourcesKey == R.array.additional_cbs_channels_strings) {
+ switch (range.mAlertType) {
+ case DEFAULT:
+ return R.string.pws_other_message_identifiers;
+ case ETWS_EARTHQUAKE:
+ return R.string.etws_earthquake_warning;
+ case ETWS_TSUNAMI:
+ return R.string.etws_tsunami_warning;
+ case TEST:
+ return R.string.etws_test_message;
+ case ETWS_DEFAULT:
+ case OTHER:
+ return R.string.etws_other_emergency_type;
+ default:
+ break;
+ }
}
return R.string.pws_other_message_identifiers;
} else {
@@ -464,18 +438,18 @@
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
context, subId);
if (channelManager.isEmergencyMessage(message)) {
- ArrayList<CellBroadcastChannelRange> ranges =
- channelManager.getCellBroadcastChannelRanges(
- R.array.additional_cbs_channels_strings);
- for (CellBroadcastChannelRange range : ranges) {
- if (serviceCategory >= range.mStartId && serviceCategory <= range.mEndId) {
- // Apply the closest title to the specified tones.
- switch (range.mAlertType) {
- case ETWS_EARTHQUAKE:
- return R.drawable.pict_icon_earthquake;
- case ETWS_TSUNAMI:
- return R.drawable.pict_icon_tsunami;
- }
+ if (channelManager.getCellBroadcastChannelResourcesKey(serviceCategory)
+ == R.array.additional_cbs_channels_strings) {
+ CellBroadcastChannelRange range = channelManager
+ .getCellBroadcastChannelRangeFromMessage(message);
+ // Apply the closest title to the specified tones.
+ switch (range.mAlertType) {
+ case ETWS_EARTHQUAKE:
+ return R.drawable.pict_icon_earthquake;
+ case ETWS_TSUNAMI:
+ return R.drawable.pict_icon_tsunami;
+ default:
+ break;
}
}
return -1;
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
index a5c9caa..a7b71a6 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
@@ -27,12 +27,11 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
-import android.os.PersistableBundle;
import android.os.UserManager;
import android.os.Vibrator;
-import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -48,7 +47,6 @@
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
import com.android.settingslib.widget.MainSwitchPreference;
@@ -152,6 +150,9 @@
// For watch layout
private static final String KEY_WATCH_ALERT_REMINDER = "watch_alert_reminder";
+ // For top introduction info
+ private static final String KEY_PREFS_TOP_INTRO = "alert_prefs_top_intro";
+
// Whether to receive alert in second language code
public static final String KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE =
"receive_cmas_in_second_language";
@@ -161,6 +162,9 @@
// Resource cache
private static final Map<Integer, Resources> sResourcesCache = new HashMap<>();
+ // Resource cache per operator
+ private static final Map<String, Resources> sResourcesCacheByOperator = new HashMap<>();
+
// Intent sent from cellbroadcastreceiver to notify cellbroadcastservice that area info update
// is disabled/enabled.
private static final String AREA_INFO_UPDATE_ACTION =
@@ -326,6 +330,9 @@
// on/off switch in settings for receiving alert in second language code
private TwoStatePreference mReceiveCmasInSecondLanguageCheckBox;
+ // Show the top introduction
+ private Preference mTopIntroPreference;
+
private final BroadcastReceiver mTestingModeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -404,6 +411,7 @@
mAlertCategory = (PreferenceCategory)
findPreference(KEY_CATEGORY_EMERGENCY_ALERTS);
}
+ mTopIntroPreference = findPreference(KEY_PREFS_TOP_INTRO);
}
@Override
@@ -576,8 +584,9 @@
private void updatePreferenceVisibility() {
Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext());
+ // The settings should be based on the config by the subscription
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
- getContext(), SubscriptionManager.getDefaultSubscriptionId());
+ getContext(), SubscriptionManager.getDefaultSubscriptionId(), null);
if (mMasterToggle != null) {
mMasterToggle.setVisible(res.getBoolean(R.bool.show_main_switch_settings));
@@ -701,6 +710,18 @@
|| getActivity().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_WATCH));
}
+
+ if (mTopIntroPreference != null) {
+ mTopIntroPreference.setTitle(getTopIntroduction());
+ }
+ }
+
+ private int getTopIntroduction() {
+ // Only set specific top introduction for roaming support now
+ if (!CellBroadcastReceiver.getRoamingOperatorSupported(getContext()).isEmpty()) {
+ return R.string.top_intro_roaming_text;
+ }
+ return R.string.top_intro_default_text;
}
private void initReminderIntervalList() {
@@ -806,9 +827,20 @@
}
public static boolean isTestAlertsToggleVisible(Context context) {
+ return isTestAlertsToggleVisible(context, null);
+ }
+
+ /**
+ * Check whether test alert toggle is visible
+ * @param context Context
+ * @param operator Opeator numeric
+ */
+ public static boolean isTestAlertsToggleVisible(Context context, String operator) {
CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context,
- SubscriptionManager.getDefaultSubscriptionId());
- Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(context);
+ SubscriptionManager.getDefaultSubscriptionId(), operator);
+ Resources res = operator == null ? getResourcesForDefaultSubId(context)
+ : getResourcesByOperator(context,
+ SubscriptionManager.getDefaultSubscriptionId(), operator);
boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges(
R.array.required_monthly_test_range_strings).isEmpty()
|| (!channelManager.getCellBroadcastChannelRanges(
@@ -870,4 +902,83 @@
public static @NonNull Resources getResourcesForDefaultSubId(@NonNull Context context) {
return getResources(context, SubscriptionManager.getDefaultSubscriptionId());
}
+
+ /**
+ * Get the resources per network operator
+ * @param context Context
+ * @param operator Opeator numeric
+ * @return the Resources based on network operator
+ */
+ public static @NonNull Resources getResourcesByOperator(
+ @NonNull Context context, int subId, @NonNull String operator) {
+ if (operator == null || operator.isEmpty()) {
+ return getResources(context, subId);
+ }
+
+ Resources res = sResourcesCacheByOperator.get(operator);
+ if (res != null) {
+ return res;
+ }
+
+ Configuration overrideConfig = new Configuration();
+ try {
+ int mcc = Integer.parseInt(operator.substring(0, 3));
+ int mnc = operator.length() > 3 ? Integer.parseInt(operator.substring(3))
+ : Configuration.MNC_ZERO;
+
+ overrideConfig.mcc = mcc;
+ overrideConfig.mnc = mnc;
+ } catch (NumberFormatException e) {
+ // should not happen
+ Log.e(TAG, "invalid operator: " + operator);
+ return context.getResources();
+ }
+
+ Context newContext = context.createConfigurationContext(overrideConfig);
+ res = newContext.getResources();
+
+ sResourcesCacheByOperator.put(operator, res);
+ return res;
+ }
+
+ /**
+ * Get the resources id which is used for the default value of the preference
+ * @param key the preference key
+ * @return a valid resources id if the key is valid and the default value is
+ * defined, otherwise 0
+ */
+ public static int getResourcesIdForDefaultPrefValue(String key) {
+ switch (key) {
+ case KEY_ENABLE_ALERTS_MASTER_TOGGLE:
+ return R.bool.master_toggle_enabled_default;
+ case KEY_ENABLE_PUBLIC_SAFETY_MESSAGES:
+ return R.bool.public_safety_messages_enabled_default;
+ case KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN:
+ return R.bool.public_safety_messages_full_screen_enabled_default;
+ case KEY_ENABLE_EMERGENCY_ALERTS:
+ return R.bool.emergency_alerts_enabled_default;
+ case KEY_ENABLE_ALERT_SPEECH:
+ return R.bool.enable_alert_speech_default;
+ case KEY_OVERRIDE_DND:
+ return R.bool.override_dnd_default;
+ case KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS:
+ return R.bool.extreme_threat_alerts_enabled_default;
+ case KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS:
+ return R.bool.severe_threat_alerts_enabled_default;
+ case KEY_ENABLE_CMAS_AMBER_ALERTS:
+ return R.bool.amber_alerts_enabled_default;
+ case KEY_ENABLE_TEST_ALERTS:
+ return R.bool.test_alerts_enabled_default;
+ case KEY_ENABLE_EXERCISE_ALERTS:
+ return R.bool.test_exercise_alerts_enabled_default;
+ case KEY_OPERATOR_DEFINED_ALERTS:
+ return R.bool.test_operator_defined_alerts_enabled_default;
+ case KEY_ENABLE_STATE_LOCAL_TEST_ALERTS:
+ return R.bool.state_local_test_alerts_enabled_default;
+ case KEY_ENABLE_AREA_UPDATE_INFO_ALERTS:
+ return R.bool.area_update_info_alerts_enabled_default;
+ default:
+ return 0;
+ }
+ }
}
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastAlertServiceTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastAlertServiceTest.java
index 00cd8c9..fb45b88 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastAlertServiceTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastAlertServiceTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -80,6 +81,8 @@
@Before
public void setUp() throws Exception {
super.setUp();
+ // No roaming supported by default
+ doReturn("").when(mMockedSharedPreferences).getString(anyString(), anyString());
}
@After
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastChannelManagerTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastChannelManagerTest.java
index cfd58fa..f916dd0 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastChannelManagerTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastChannelManagerTest.java
@@ -20,7 +20,13 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -35,42 +41,84 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* APN retry manager tests
*/
public class CellBroadcastChannelManagerTest extends CellBroadcastTest {
+ private static final String[] CHANNEL_CONFIG1 = {
+ "12:type=etws_earthquake, emergency=true, display=false, always_on=true",
+ "456:type=etws_tsunami, emergency=true, alert_duration=60000, scope=domestic",
+ "0xAC00-0xAFED:type=other, emergency=false, override_dnd=true, scope=carrier",
+ "54-60:emergency=true, testing_mode=true, dialog_with_notification=true",
+ "100-200",
+ "0xA804:type=test, emergency=true, exclude_from_sms_inbox=true, vibration=0|350|250|350",
+ "0x111E:debug_build=true"};
+ private static final String[] CHANNEL_CONFIG2 = {
+ "12:type=etws_earthquake, emergency=true, display=true, always_on=false",
+ "456:type=etws_tsunami, emergency=true, alert_duration=20000, scope=domestic",
+ "0xAC00-0xAEFF:type=other, emergency=false, override_dnd=true, scope=carrier"};
+ private static final String[] CHANNEL_CONFIG3 = {
+ "0xA804:type=test, emergency=true, exclude_from_sms_inbox=true, vibration=0|350|250|350"
+ };
+
+ private static final String OPERATOR = "123456";
+ private static final int SUB_ID = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+
+ // For SUB1 without roaming support
+ private CellBroadcastChannelManager mChannelManager1;
+ // For SUB1 with roaming support of OPERATOR
+ private CellBroadcastChannelManager mChannelManager2;
+
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
+
+ doReturn(null).when(mTelephonyManager).getServiceState();
+ doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+ doReturn(mContext).when(mContext).createConfigurationContext(any());
+
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
+ // Init mChannelManager1 for SUB1
+ putResources(com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings,
+ CHANNEL_CONFIG1);
+ mChannelManager1 = new CellBroadcastChannelManager(mContext, SUB_ID, null, false);
+
+ // Init mChannelManager2 for SUB2 and OPERATOR
+ putResources(com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings,
+ CHANNEL_CONFIG2);
+ putResources(
+ com.android.cellbroadcastreceiver.R.array.emergency_alerts_channels_range_strings,
+ CHANNEL_CONFIG3);
+ mChannelManager2 = new CellBroadcastChannelManager(mContext, SUB_ID, OPERATOR, false);
}
@After
public void tearDown() throws Exception {
super.tearDown();
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
}
@Test
@SmallTest
public void testGetCellBroadcastChannelRanges() throws Exception {
- putResources(com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings,
- new String[]{
- "12:type=etws_earthquake, emergency=true, display=false, always_on=true",
- "456:type=etws_tsunami, emergency=true, alert_duration=60000, "
- + "scope=domestic", "0xAC00-0xAFED:type=other, emergency=false, "
- + "override_dnd=true, scope=carrier", "54-60:emergency=true, "
- + "testing_mode=true, " + "dialog_with_notification=true",
- "100-200", "0xA804:type=test, "
- + "emergency=true, exclude_from_sms_inbox=true, vibration=0|350|250|350",
- "0x111E:debug_build=true"});
-
- CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(mContext,
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false);
-
- ArrayList<CellBroadcastChannelRange> list = channelManager.getCellBroadcastChannelRanges(
+ List<CellBroadcastChannelRange> list = mChannelManager1.getCellBroadcastChannelRanges(
com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings);
+ verifyChannelRangesForConfig1(list);
+
+ list = mChannelManager2.getCellBroadcastChannelRanges(
+ com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings);
+
+ verifyChannelRangesForConfig2(list);
+ }
+
+ private void verifyChannelRangesForConfig1(List<CellBroadcastChannelRange> list)
+ throws Exception {
+ assertEquals(6, list.size());
+
assertEquals(12, list.get(0).mStartId);
assertEquals(12, list.get(0).mEndId);
assertEquals(AlertType.ETWS_EARTHQUAKE, list.get(0).mAlertType);
@@ -140,7 +188,124 @@
assertTrue(Arrays.equals(new int[]{0, 350, 250, 350}, list.get(5).mVibrationPattern));
assertNotEquals(list.get(4).toString(), list.get(5).toString());
assertFalse(list.get(5).mDisplayDialogWithNotification);
+ }
- assertEquals(6, list.size());
+ private void verifyChannelRangesForConfig2(List<CellBroadcastChannelRange> list)
+ throws Exception {
+ assertEquals(3, list.size());
+
+ assertEquals(12, list.get(0).mStartId);
+ assertEquals(12, list.get(0).mEndId);
+ assertEquals(AlertType.ETWS_EARTHQUAKE, list.get(0).mAlertType);
+ assertEquals(CellBroadcastChannelRange.LEVEL_EMERGENCY, list.get(0).mEmergencyLevel);
+ assertFalse(list.get(0).mAlwaysOn);
+ assertTrue(list.get(0).mDisplay);
+ assertFalse(list.get(0).mOverrideDnd);
+ assertTrue(list.get(0).mWriteToSmsInbox);
+ assertFalse(list.get(0).mTestMode);
+ assertFalse(list.get(0).mDisplayDialogWithNotification);
+
+ assertEquals(456, list.get(1).mStartId);
+ assertEquals(456, list.get(1).mEndId);
+ assertEquals(AlertType.ETWS_TSUNAMI, list.get(1).mAlertType);
+ assertEquals(CellBroadcastChannelRange.LEVEL_EMERGENCY, list.get(1).mEmergencyLevel);
+ assertFalse(list.get(1).mAlwaysOn);
+ assertTrue(list.get(1).mDisplay);
+ assertFalse(list.get(1).mOverrideDnd);
+ assertTrue(list.get(1).mWriteToSmsInbox);
+ assertFalse(list.get(1).mTestMode);
+ assertEquals(20000, list.get(1).mAlertDuration);
+ assertFalse(list.get(1).mDisplayDialogWithNotification);
+
+ assertEquals(0xAC00, list.get(2).mStartId);
+ assertEquals(0xAEFF, list.get(2).mEndId);
+ assertEquals(AlertType.OTHER, list.get(2).mAlertType);
+ assertEquals(CellBroadcastChannelRange.LEVEL_NOT_EMERGENCY, list.get(2).mEmergencyLevel);
+ assertFalse(list.get(2).mAlwaysOn);
+ assertTrue(list.get(2).mDisplay);
+ assertTrue(list.get(2).mOverrideDnd);
+ assertTrue(list.get(2).mWriteToSmsInbox);
+ assertFalse(list.get(2).mTestMode);
+ assertEquals(list.get(2).mScope, CellBroadcastChannelRange.SCOPE_CARRIER);
+ assertFalse(list.get(2).mDisplayDialogWithNotification);
+ }
+
+ @Test
+ @SmallTest
+ public void testGetCellBroadcastChannelResourcesKey() throws Exception {
+ assertEquals(mChannelManager1.getCellBroadcastChannelResourcesKey(0xA804),
+ com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings);
+
+ assertEquals(mChannelManager2.getCellBroadcastChannelResourcesKey(0xA804),
+ com.android.cellbroadcastreceiver.R.array.emergency_alerts_channels_range_strings);
+ // It should hit the channel ranges for sub as no config for the operator
+ assertEquals(mChannelManager2.getCellBroadcastChannelResourcesKey(0xAFED),
+ com.android.cellbroadcastreceiver.R.array.additional_cbs_channels_strings);
+ }
+
+ @Test
+ @SmallTest
+ public void testGetCellBroadcastChannelRange() throws Exception {
+ CellBroadcastChannelRange channelRange = mChannelManager1
+ .getCellBroadcastChannelRange(0xAC00);
+
+ assertEquals(0xAC00, channelRange.mStartId);
+ assertEquals(0xAFED, channelRange.mEndId);
+
+ channelRange = mChannelManager2.getCellBroadcastChannelRange(0xAC00);
+
+ assertEquals(0xAC00, channelRange.mStartId);
+ assertEquals(0xAEFF, channelRange.mEndId);
+ }
+
+ @Test
+ @SmallTest
+ public void testGetAllCellBroadcastChannelRanges() throws Exception {
+ List<CellBroadcastChannelRange> ranges =
+ mChannelManager1.getAllCellBroadcastChannelRanges();
+
+ verifyChannelRangesForConfig1(ranges);
+
+ ranges = mChannelManager2.getAllCellBroadcastChannelRanges();
+
+ assertEquals(10, ranges.size());
+ verifyChannelRangesForConfig2(new ArrayList<>(ranges).subList(0, 3));
+ verifyChannelRangesForConfig1(new ArrayList<>(ranges).subList(4, 10));
+ }
+
+ @Test
+ @SmallTest
+ public void testGetCellBroadcastChannelRangeFromMessage() throws Exception {
+ SmsCbMessage msg = createMessageForCmasMessageClass(1, 0xAC00, 0);
+
+ CellBroadcastChannelRange range = mChannelManager1
+ .getCellBroadcastChannelRangeFromMessage(msg);
+
+ assertEquals(0xAC00, range.mStartId);
+ assertEquals(0xAFED, range.mEndId);
+
+ range = mChannelManager2.getCellBroadcastChannelRangeFromMessage(msg);
+
+ assertEquals(0xAC00, range.mStartId);
+ assertEquals(0xAEFF, range.mEndId);
+ }
+
+ @Test
+ @SmallTest
+ public void testIsEmergencyMessage() throws Exception {
+ assertFalse(mChannelManager1.isEmergencyMessage(null));
+
+ SmsCbMessage msg = createMessageForCmasMessageClass(1, 0xA804, 0);
+
+ assertTrue(mChannelManager1.isEmergencyMessage(msg));
+ }
+
+ private SmsCbMessage createMessageForCmasMessageClass(int serialNumber,
+ int serviceCategory, int cmasMessageClass) {
+ return new SmsCbMessage(1, 2, serialNumber, new SmsCbLocation(), serviceCategory,
+ "language", "body",
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, null,
+ new SmsCbCmasInfo(cmasMessageClass, 2, 3, 4, 5, 6),
+ 0, SUB_ID);
}
}
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastConfigServiceTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastConfigServiceTest.java
index 72d802f..6d60b8c 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastConfigServiceTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastConfigServiceTest.java
@@ -17,18 +17,24 @@
package com.android.cellbroadcastreceiver.unit;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.SmsCbMessage;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -62,6 +68,15 @@
@Mock
SharedPreferences mMockedSharedPreferences;
+ @Mock
+ SubscriptionManager mMockSubscriptionManager;
+
+ @Mock
+ SubscriptionInfo mMockSubscriptionInfo;
+
+ @Mock
+ Intent mIntent;
+
private CellBroadcastConfigService mConfigService;
@Before
@@ -140,20 +155,20 @@
TelephonyManager.enableServiceHandleCaching();
}
- private void setCellBroadcastRange(int subId, boolean enable,
- List<CellBroadcastChannelRange> ranges)
- throws Exception {
+ private void setCellBroadcastRange(int subId, boolean isEnableOnly,
+ boolean enable, List<CellBroadcastChannelRange> ranges) throws Exception {
- Class[] cArgs = new Class[3];
+ Class[] cArgs = new Class[4];
cArgs[0] = Integer.TYPE;
cArgs[1] = Boolean.TYPE;
- cArgs[2] = List.class;
+ cArgs[2] = Boolean.TYPE;
+ cArgs[3] = List.class;
Method method =
CellBroadcastConfigService.class.getDeclaredMethod("setCellBroadcastRange", cArgs);
method.setAccessible(true);
- method.invoke(mConfigService, subId, enable, ranges);
+ method.invoke(mConfigService, subId, isEnableOnly, enable, ranges);
}
/**
@@ -164,8 +179,8 @@
public void testEnableCellBroadcastRange() throws Exception {
ArrayList<CellBroadcastChannelRange> result = new ArrayList<>();
result.add(new CellBroadcastChannelRange(mContext,
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, "10-20"));
- setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, result);
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mResources, "10-20"));
+ setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, true, result);
ArgumentCaptor<Integer> captorStart = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> captorEnd = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> captorType = ArgumentCaptor.forClass(Integer.class);
@@ -176,6 +191,14 @@
assertEquals(10, captorStart.getValue().intValue());
assertEquals(20, captorEnd.getValue().intValue());
assertEquals(1, captorType.getValue().intValue());
+
+ setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, true, result);
+
+ verify(mMockedSmsService, times(2)).enableCellBroadcastRangeForSubscriber(anyInt(),
+ captorStart.capture(), captorEnd.capture(), captorType.capture());
+ assertEquals(10, captorStart.getValue().intValue());
+ assertEquals(20, captorEnd.getValue().intValue());
+ assertEquals(1, captorType.getValue().intValue());
}
/**
@@ -186,8 +209,8 @@
public void testDisableCellBroadcastRange() throws Exception {
ArrayList<CellBroadcastChannelRange> result = new ArrayList<>();
result.add(new CellBroadcastChannelRange(mContext,
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, "10-20"));
- setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, result);
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mResources, "10-20"));
+ setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, false, result);
ArgumentCaptor<Integer> captorStart = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> captorEnd = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> captorType = ArgumentCaptor.forClass(Integer.class);
@@ -198,6 +221,11 @@
assertEquals(10, captorStart.getValue().intValue());
assertEquals(20, captorEnd.getValue().intValue());
assertEquals(1, captorType.getValue().intValue());
+
+ setCellBroadcastRange(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, false, result);
+
+ verify(mMockedSmsService, times(1)).disableCellBroadcastRangeForSubscriber(anyInt(),
+ captorStart.capture(), captorEnd.capture(), captorType.capture());
}
private void setPreference(String pref, boolean value) {
@@ -634,4 +662,171 @@
eq(SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE),
eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
}
+
+ /**
+ * Test handling the intent to enable channels
+ */
+ @Test
+ @SmallTest
+ public void testOnHandleIntentActionEnableChannels() throws Exception {
+ List<SubscriptionInfo> sl = new ArrayList<>();
+ sl.add(mMockSubscriptionInfo);
+ doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(
+ mMockSubscriptionInfo).getSubscriptionId();
+ doReturn(mContext).when(mConfigService).getApplicationContext();
+ doReturn(mMockSubscriptionManager).when(mContext).getSystemService(anyString());
+ doReturn(sl).when(mMockSubscriptionManager).getActiveSubscriptionInfoList();
+ doReturn(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS).when(mIntent).getAction();
+ doNothing().when(mConfigService).enableCellBroadcastChannels(anyInt());
+ doNothing().when(mConfigService).enableCellBroadcastRoamingChannelsAsNeeded(anyInt());
+
+ Method method = CellBroadcastConfigService.class.getDeclaredMethod(
+ "onHandleIntent", new Class[]{Intent.class});
+ method.setAccessible(true);
+ method.invoke(mConfigService, mIntent);
+
+ verify(mConfigService, times(1)).enableCellBroadcastChannels(
+ eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ verify(mConfigService, times(1)).enableCellBroadcastRoamingChannelsAsNeeded(
+ eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ /**
+ * Test enabling cell broadcast roaming channels as needed
+ */
+ @Test
+ @SmallTest
+ public void testEnableCellBroadcastRoamingChannelsAsNeeded() throws Exception {
+ doReturn("").when(mMockedSharedPreferences).getString(anyString(), anyString());
+
+ mConfigService.enableCellBroadcastRoamingChannelsAsNeeded(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+
+ //do nothing if operator is empty
+ verify(mConfigService, never()).getResources(anyInt(), anyString());
+
+ Context mockContext = mock(Context.class);
+ doReturn(mResources).when(mockContext).getResources();
+ doReturn(mockContext).when(mContext).createConfigurationContext(any());
+ doReturn("123").when(mMockedSharedPreferences).getString(anyString(), anyString());
+ doReturn(mResources).when(mConfigService).getResources(anyInt(), anyString());
+ putResources(com.android.cellbroadcastreceiver.R.bool.master_toggle_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .extreme_threat_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .severe_threat_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool.amber_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool.show_test_settings, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool.test_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .test_exercise_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .test_operator_defined_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .area_update_info_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .public_safety_messages_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .state_local_test_alerts_enabled_default, true);
+ putResources(com.android.cellbroadcastreceiver.R.bool
+ .emergency_alerts_enabled_default, true);
+
+ mConfigService.enableCellBroadcastRoamingChannelsAsNeeded(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+
+ // should not disable channel
+ verify(mMockedSmsService, never()).disableCellBroadcastRangeForSubscriber(
+ anyInt(), anyInt(), anyInt(), anyInt());
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP2));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP2));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP2));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP2));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE),
+ eq(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP2));
+
+ // GSM
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE),
+ eq(SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+
+ verify(mMockedSmsService, times(1)).enableCellBroadcastRangeForSubscriber(
+ eq(0),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE),
+ eq(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE),
+ eq(SmsCbMessage.MESSAGE_FORMAT_3GPP));
+ }
}
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastReceiverTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastReceiverTest.java
index 76b37c9..8b6377c 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastReceiverTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastReceiverTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
@@ -43,6 +44,7 @@
import android.os.UserManager;
import android.provider.Telephony;
import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaSmsCbProgramData;
@@ -470,6 +472,128 @@
mCellBroadcastReceiver.onReceive(mContext, mIntent);
}
+ @Test
+ public void testOnServiceStateChange() {
+ mFakeSharedPreferences.putInt("service_state", ServiceState.STATE_OUT_OF_SERVICE);
+ mFakeSharedPreferences.putString("roaming_operator_supported", "");
+ mockTelephonyManager();
+ doReturn("android.intent.action.SERVICE_STATE").when(mIntent).getAction();
+ doReturn(ServiceState.STATE_IN_SERVICE).when(mIntent).getIntExtra(anyString(), anyInt());
+ doReturn(false).when(mMockTelephonyManager).isNetworkRoaming();
+ doReturn("123456").when(mMockTelephonyManager).getNetworkOperator();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, never()).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getInt("service_state", ServiceState.STATE_POWER_OFF))
+ .isEqualTo(ServiceState.STATE_IN_SERVICE);
+
+ mFakeSharedPreferences.putInt("service_state", ServiceState.STATE_POWER_OFF);
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getInt("service_state", ServiceState.STATE_POWER_OFF))
+ .isEqualTo(ServiceState.STATE_IN_SERVICE);
+ }
+
+
+ @Test
+ public void testOnNetworkRoamingChange() {
+ mFakeSharedPreferences.putInt("service_state", ServiceState.STATE_IN_SERVICE);
+ mFakeSharedPreferences.putString("roaming_operator_supported", "");
+ mockTelephonyManager();
+ doReturn("android.intent.action.SERVICE_STATE").when(mIntent).getAction();
+ doReturn(ServiceState.STATE_IN_SERVICE).when(mIntent).getIntExtra(anyString(), anyInt());
+ doReturn("123456").when(mMockTelephonyManager).getNetworkOperator();
+
+ // not roaming, verify not to store the network operator, or call enable channel
+ doReturn(false).when(mMockTelephonyManager).isNetworkRoaming();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, never()).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "123456")).isEqualTo("");
+
+ // roaming and network operator changed with wild match, verify to
+ // update the network operator, and call enable channel
+ doReturn(true).when(mMockTelephonyManager).isNetworkRoaming();
+ doReturn(new String[] {"XXXXXX"}).when(mResources).getStringArray(anyInt());
+ doReturn("654321").when(mMockTelephonyManager).getSimOperator();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(1)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "")).isEqualTo("123456");
+
+ // roaming to home case, verify to call enable channel
+ doReturn(false).when(mMockTelephonyManager).isNetworkRoaming();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(2)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "123456")).isEqualTo("");
+
+ // roaming and network operator changed with exact mcc match, verify to
+ // update the network operator, and call enable channel
+ doReturn(true).when(mMockTelephonyManager).isNetworkRoaming();
+ doReturn(new String[] {"123"}).when(mResources).getStringArray(anyInt());
+ doReturn("654321").when(mMockTelephonyManager).getSimOperator();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(3)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "")).isEqualTo("123");
+
+ // roaming to network operator with same mcc and configured as exact mcc match,
+ // verify to update the network operator, but not call enable channel
+ doReturn("123654").when(mMockTelephonyManager).getNetworkOperator();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(3)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "")).isEqualTo("123");
+
+ // roaming and network operator changed with exact match, verify to
+ // update the network operator, and call enable channel
+ doReturn(new String[] {"123456"}).when(mResources).getStringArray(anyInt());
+ doReturn("123456").when(mMockTelephonyManager).getNetworkOperator();
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(4)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "")).isEqualTo("123456");
+
+ // roaming to network operator with different mcc and configured as any mcc match,
+ // verify to update the network operator, and call enable channel
+ doReturn("321456").when(mMockTelephonyManager).getNetworkOperator();
+ doReturn(new String[] {"XXX"}).when(mResources).getStringArray(anyInt());
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(5)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "")).isEqualTo("321");
+
+ // roaming to network operator which does not match the configuration,
+ // verify to update the network operator to empty, and call enable channel
+ doReturn("321456").when(mMockTelephonyManager).getNetworkOperator();
+ doReturn(new String[] {"123"}).when(mResources).getStringArray(anyInt());
+
+ mCellBroadcastReceiver.onReceive(mContext, mIntent);
+
+ verify(mCellBroadcastReceiver, times(6)).startConfigServiceToEnableChannels();
+ assertThat(mFakeSharedPreferences.getString(
+ "roaming_operator_supported", "321")).isEqualTo("");
+ }
+
+
@After
public void tearDown() throws Exception {
super.tearDown();
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastServiceTestCase.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastServiceTestCase.java
index 66ae7b1..2e767fe 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastServiceTestCase.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastServiceTestCase.java
@@ -37,7 +37,7 @@
import android.telephony.TelephonyManager;
import android.test.ServiceTestCase;
-import com.android.cellbroadcastreceiver.CellBroadcastSettings;
+import com.android.cellbroadcastreceiver.CellBroadcastChannelManager;
import com.android.internal.telephony.ISub;
import org.junit.After;
@@ -173,11 +173,13 @@
mContext = new TestContextWrapper(getContext());
setContext(mContext);
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
}
@After
public void tearDown() throws Exception {
mMockedServiceManager.restoreAllServices();
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
}
void putResources(int id, String[] values) {
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastSettingsTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastSettingsTest.java
index ca34ac6..f893f8c 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastSettingsTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastSettingsTest.java
@@ -33,6 +33,7 @@
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Looper;
import android.os.RemoteException;
@@ -52,6 +53,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@RunWith(AndroidJUnit4.class)
public class CellBroadcastSettingsTest extends
@@ -201,6 +203,34 @@
verify(mockContext2, times(1)).getResources();
}
+ @Test
+ public void testGetResourcesByOperator() {
+ Context mockContext = mock(Context.class);
+ Resources mockResources = mock(Resources.class);
+ doReturn(mockResources).when(mockContext).getResources();
+
+ CellBroadcastSettings.getResourcesByOperator(mockContext,
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, "");
+ verify(mockContext, never()).createConfigurationContext(any());
+ verify(mockContext, times(1)).getResources();
+
+ int mcc = 123;
+ int mnc = 456;
+ Context mockContext2 = mock(Context.class);
+ ArgumentCaptor<Configuration> captorConfig = ArgumentCaptor.forClass(Configuration.class);
+ doReturn(mockResources).when(mockContext2).getResources();
+ doReturn(mockContext2).when(mockContext).createConfigurationContext(any());
+
+ CellBroadcastSettings.getResourcesByOperator(mockContext,
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ Integer.toString(mcc) + Integer.toString(mnc));
+ verify(mockContext, times(1)).getResources();
+ verify(mockContext2, times(1)).getResources();
+ verify(mockContext, times(1)).createConfigurationContext(captorConfig.capture());
+ assertEquals(mcc, captorConfig.getValue().mcc);
+ assertEquals(mnc, captorConfig.getValue().mnc);
+ }
+
public void waitUntilDialogOpens(Runnable r, long maxWaitMs) {
long waitTime = 0;
while (waitTime < maxWaitMs) {
diff --git a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastTest.java b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastTest.java
index 54c6329..e4c80a3 100644
--- a/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastTest.java
+++ b/tests/unit/src/com/android/cellbroadcastreceiver/unit/CellBroadcastTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.eq;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
@@ -30,6 +31,7 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.cellbroadcastreceiver.CellBroadcastChannelManager;
import com.android.internal.telephony.ISub;
import org.mockito.Mock;
@@ -53,10 +55,14 @@
Resources mResources;
@Mock
ISub.Stub mSubService;
+ @Mock
+ SharedPreferences mSharedPreferences;
protected void setUp(String tag) throws Exception {
TAG = tag;
MockitoAnnotations.initMocks(this);
+ doReturn(mSharedPreferences).when(mContext).getSharedPreferences(anyString(), anyInt());
+ doReturn(null).when(mSharedPreferences).getString(anyString(), anyString());
// A hack to return mResources from static method
// CellBroadcastSettings.getResources(context).
doReturn(mSubService).when(mSubService).queryLocalInterface(anyString());
@@ -70,6 +76,7 @@
SubscriptionManager.disableCaching();
initContext();
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
}
private void initContext() {
@@ -97,8 +104,13 @@
doReturn(values).when(mResources).getStringArray(eq(id));
}
+ void putResources(int id, boolean values) {
+ doReturn(values).when(mResources).getBoolean(eq(id));
+ }
+
protected void tearDown() throws Exception {
mMockedServiceManager.restoreAllServices();
+ CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
}
protected static void logd(String s) {