1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cellbroadcastreceiver; 18 19 import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.VDBG; 20 import static com.android.cellbroadcastservice.CellBroadcastMetrics.ERRSRC_CBR; 21 import static com.android.cellbroadcastservice.CellBroadcastMetrics.ERRTYPE_CHANNEL_R; 22 import static com.android.cellbroadcastservice.CellBroadcastMetrics.ERRTYPE_ENABLECHANNEL; 23 24 import android.Manifest; 25 import android.app.IntentService; 26 import android.app.Notification; 27 import android.app.NotificationManager; 28 import android.app.PendingIntent; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.SharedPreferences; 32 import android.content.res.Resources; 33 import android.preference.PreferenceManager; 34 import android.telephony.CellBroadcastIdRange; 35 import android.telephony.SmsManager; 36 import android.telephony.SubscriptionInfo; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.TelephonyManager; 39 import android.text.TextUtils; 40 import android.util.Log; 41 import android.util.Pair; 42 43 import androidx.annotation.NonNull; 44 45 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.modules.utils.build.SdkLevel; 48 49 import java.lang.reflect.Method; 50 import java.util.ArrayList; 51 import java.util.HashSet; 52 import java.util.List; 53 54 /** 55 * This service manages enabling and disabling ranges of message identifiers 56 * that the radio should listen for. It operates independently of the other 57 * services and runs at boot time and after exiting airplane mode. 58 * 59 * Note that the entire range of emergency channels is enabled. Test messages 60 * and lower priority broadcasts are filtered out in CellBroadcastAlertService 61 * if the user has not enabled them in settings. 62 * 63 * TODO: add notification to re-enable channels after a radio reset. 64 */ 65 public class CellBroadcastConfigService extends IntentService { 66 private static final String TAG = "CellBroadcastConfigService"; 67 68 private HashSet<Pair<Integer, Integer>> mChannelRangeForMetric = new HashSet<>(); 69 70 @VisibleForTesting 71 public static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS"; 72 public static final String ACTION_UPDATE_SETTINGS_FOR_CARRIER = "UPDATE_SETTINGS_FOR_CARRIER"; 73 public static final String ACTION_RESET_SETTINGS_AS_NEEDED = "RESET_SETTINGS_AS_NEEDED"; 74 75 public static final String EXTRA_SUB = "SUB"; 76 77 private static final String ACTION_SET_CHANNELS_DONE = 78 "android.cellbroadcast.compliancetest.SET_CHANNELS_DONE"; 79 /** 80 * CbConfig is consisted by starting channel id, ending channel id, and ran type, 81 * whether it should be enabled or not 82 */ 83 public static class CbConfig { 84 public int mStartId; 85 public int mEndId; 86 public int mRanType; 87 public boolean mEnable; 88 CbConfig(int startId, int endId, int type, boolean enable)89 public CbConfig(int startId, int endId, int type, boolean enable) { 90 this.mStartId = startId; 91 this.mEndId = endId; 92 this.mRanType = type; 93 this.mEnable = enable; 94 } 95 } 96 CellBroadcastConfigService()97 public CellBroadcastConfigService() { 98 super(TAG); // use class name for worker thread name 99 } 100 101 @Override onHandleIntent(Intent intent)102 protected void onHandleIntent(Intent intent) { 103 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 104 try { 105 SubscriptionManager subManager = (SubscriptionManager) getApplicationContext() 106 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 107 108 if (subManager != null) { 109 mChannelRangeForMetric.clear(); 110 // Retrieve all the active subscription inside and enable cell broadcast 111 // messages on all subs. The duplication detection will be done at the 112 // frameworks. 113 int[] subIds = getActiveSubIdList(subManager); 114 if (subIds.length != 0) { 115 for (int subId : subIds) { 116 log("Enable CellBroadcast on sub " + subId); 117 enableCellBroadcastChannels(subId); 118 if (!SdkLevel.isAtLeastU()) { 119 broadcastSetChannelsIsDone(subId); 120 } 121 } 122 } else { 123 // For no sim scenario. 124 enableCellBroadcastChannels(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 125 } 126 127 String roamingOperator = CellBroadcastReceiver.getRoamingOperatorSupported( 128 this); 129 CellBroadcastReceiverMetrics.getInstance().onConfigUpdated( 130 getApplicationContext(), 131 roamingOperator.isEmpty() ? "" : roamingOperator, 132 mChannelRangeForMetric); 133 } 134 } catch (Exception ex) { 135 CellBroadcastReceiverMetrics.getInstance().logModuleError( 136 ERRSRC_CBR, ERRTYPE_ENABLECHANNEL); 137 Log.e(TAG, "exception enabling cell broadcast channels", ex); 138 } 139 } else if (ACTION_UPDATE_SETTINGS_FOR_CARRIER.equals(intent.getAction())) { 140 Context c = getApplicationContext(); 141 if (CellBroadcastSettings.hasAnyPreferenceChanged(c)) { 142 Log.d(TAG, "Preference has changed from user set, posting notification."); 143 144 CellBroadcastAlertService.createNotificationChannels(c); 145 Intent settingsIntent = new Intent(c, CellBroadcastSettings.class); 146 PendingIntent pi = PendingIntent.getActivity(c, 147 CellBroadcastAlertService.SETTINGS_CHANGED_NOTIFICATION_ID, settingsIntent, 148 PendingIntent.FLAG_ONE_SHOT 149 | PendingIntent.FLAG_UPDATE_CURRENT 150 | PendingIntent.FLAG_IMMUTABLE); 151 152 Notification.Builder builder = new Notification.Builder(c, 153 CellBroadcastAlertService.NOTIFICATION_CHANNEL_SETTINGS_UPDATES) 154 .setCategory(Notification.CATEGORY_SYSTEM) 155 .setContentTitle(c.getString(R.string.notification_cb_settings_changed_title)) 156 .setContentText(c.getString(R.string.notification_cb_settings_changed_text)) 157 .setSmallIcon(R.drawable.ic_settings_gear_outline_24dp) 158 .setContentIntent(pi) 159 .setAutoCancel(true); 160 NotificationManager notificationManager = c.getSystemService( 161 NotificationManager.class); 162 notificationManager.notify( 163 CellBroadcastAlertService.SETTINGS_CHANGED_NOTIFICATION_ID, 164 builder.build()); 165 } 166 Log.e(TAG, "Reset all preferences"); 167 resetAllPreferences(); 168 } else if (ACTION_RESET_SETTINGS_AS_NEEDED.equals(intent.getAction())) { 169 Resources res = getResources(intent.getIntExtra( 170 EXTRA_SUB, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), null); 171 if (!CellBroadcastSettings.hasAnyPreferenceChanged(getApplicationContext()) 172 && (isMasterToggleEnabled() != res.getBoolean( 173 R.bool.master_toggle_enabled_default))) { 174 Log.d(TAG, "Reset all preferences as no user changes and master toggle is" 175 + " different as the config"); 176 resetAllPreferences(); 177 } 178 } 179 } 180 181 /** 182 * Encapsulate the static method to reset all preferences for testing purpose. 183 */ 184 @VisibleForTesting resetAllPreferences()185 public void resetAllPreferences() { 186 CellBroadcastSettings.resetAllPreferences(getApplicationContext()); 187 } 188 189 @NonNull getActiveSubIdList(SubscriptionManager subMgr)190 private int[] getActiveSubIdList(SubscriptionManager subMgr) { 191 List<SubscriptionInfo> subInfos = subMgr.getActiveSubscriptionInfoList(); 192 int size = subInfos != null ? subInfos.size() : 0; 193 int[] subIds = new int[size]; 194 for (int i = 0; i < size; i++) { 195 subIds[i] = subInfos.get(i).getSubscriptionId(); 196 } 197 return subIds; 198 } 199 200 /** 201 * reset cell broadcast ranges 202 */ 203 @VisibleForTesting resetCellBroadcastChannels(int subId)204 public void resetCellBroadcastChannels(int subId) { 205 if (SdkLevel.isAtLeastU()) { 206 return; 207 } 208 SmsManager manager; 209 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 210 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 211 } else { 212 manager = SmsManager.getDefault(); 213 } 214 // SmsManager.resetAllCellBroadcastRanges is a new @SystemAPI in S. We need to support 215 // backward compatibility as the module need to run on R build as well. 216 if (SdkLevel.isAtLeastS()) { 217 manager.resetAllCellBroadcastRanges(); 218 } else { 219 try { 220 Method method = SmsManager.class.getDeclaredMethod("resetAllCellBroadcastRanges"); 221 method.invoke(manager); 222 } catch (Exception e) { 223 CellBroadcastReceiverMetrics.getInstance().logModuleError( 224 ERRSRC_CBR, ERRTYPE_CHANNEL_R); 225 log("Can't reset cell broadcast ranges. e=" + e); 226 } 227 } 228 } 229 230 /** 231 * Enable cell broadcast messages channels. Messages can be only received on the 232 * enabled channels. 233 * 234 * @param subId Subscription index 235 */ 236 @VisibleForTesting enableCellBroadcastChannels(int subId)237 public void enableCellBroadcastChannels(int subId) { 238 resetCellBroadcastChannels(subId); 239 240 List<CbConfig> config = getCellBroadcastChannelsConfig(subId, null); 241 242 String roamingOperator = CellBroadcastReceiver.getRoamingOperatorSupported(this); 243 if (!TextUtils.isEmpty(roamingOperator)) { 244 config.addAll(getCellBroadcastChannelsConfig(subId, roamingOperator)); 245 config = mergeConfigAsNeeded(config); 246 } 247 setCellBroadcastRange(subId, config); 248 } 249 getCellBroadcastChannelsConfig(int subId, String roamingOperator)250 private List<CbConfig> getCellBroadcastChannelsConfig(int subId, String roamingOperator) { 251 252 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 253 Resources res = getResources(subId, roamingOperator); 254 boolean isRoaming = !TextUtils.isEmpty(roamingOperator); 255 256 // boolean for each user preference checkbox, true for checked, false for unchecked 257 // Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts 258 // except for always-on alerts e.g, presidential. i.e. to receive CMAS severe alerts, both 259 // enableAlertsMasterToggle AND enableCmasSevereAlerts must be true. 260 boolean enableAlertsMasterToggle = isRoaming 261 ? res.getBoolean(R.bool.master_toggle_enabled_default) : isMasterToggleEnabled(); 262 263 boolean enableEtwsAlerts = enableAlertsMasterToggle; 264 265 // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless 266 // user's preference 267 boolean enablePresidential = true; 268 269 boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && (isRoaming 270 ? res.getBoolean(R.bool.extreme_threat_alerts_enabled_default) 271 : prefs.getBoolean( 272 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true)); 273 274 boolean enableCmasSevereAlerts = enableAlertsMasterToggle && (isRoaming 275 ? res.getBoolean(R.bool.severe_threat_alerts_enabled_default) 276 : prefs.getBoolean( 277 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true)); 278 279 boolean enableCmasAmberAlerts = enableAlertsMasterToggle && (isRoaming 280 ? res.getBoolean(R.bool.amber_alerts_enabled_default) 281 : prefs.getBoolean( 282 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true)); 283 284 boolean enableTestAlerts = enableAlertsMasterToggle && (isRoaming 285 ? (CellBroadcastSettings 286 .isTestAlertsToggleVisible(getApplicationContext(), roamingOperator) 287 && res.getBoolean(R.bool.test_alerts_enabled_default)) 288 : (CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext()) 289 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, 290 false))); 291 292 boolean enableExerciseAlerts = enableAlertsMasterToggle && (isRoaming 293 ? (res.getBoolean(R.bool.show_separate_exercise_settings) 294 && res.getBoolean(R.bool.test_exercise_alerts_enabled_default)) 295 : (res.getBoolean(R.bool.show_separate_exercise_settings) 296 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_EXERCISE_ALERTS, 297 false))); 298 299 boolean enableOperatorDefined = enableAlertsMasterToggle && (isRoaming 300 ? (res.getBoolean(R.bool.show_separate_operator_defined_settings) 301 && res.getBoolean(R.bool.test_operator_defined_alerts_enabled_default)) 302 : (res.getBoolean(R.bool.show_separate_operator_defined_settings) 303 && prefs.getBoolean(CellBroadcastSettings.KEY_OPERATOR_DEFINED_ALERTS, 304 false))); 305 306 boolean enableAreaUpdateInfoAlerts = isRoaming 307 ? (res.getBoolean(R.bool.config_showAreaUpdateInfoSettings) 308 && res.getBoolean(R.bool.area_update_info_alerts_enabled_default)) 309 : (res.getBoolean(R.bool.config_showAreaUpdateInfoSettings) 310 && prefs.getBoolean( 311 CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS, false)); 312 313 boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle && (isRoaming 314 ? res.getBoolean(R.bool.public_safety_messages_enabled_default) 315 : prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES, true)); 316 317 boolean enableStateLocalTestAlerts = enableAlertsMasterToggle && (isRoaming 318 ? res.getBoolean(R.bool.state_local_test_alerts_enabled_default) 319 : (prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS, 320 false) || (!res.getBoolean(R.bool.show_state_local_test_settings) 321 && res.getBoolean(R.bool.state_local_test_alerts_enabled_default)))); 322 323 boolean enableEmergencyAlerts = enableAlertsMasterToggle && (isRoaming 324 ? res.getBoolean(R.bool.emergency_alerts_enabled_default) 325 : prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true)); 326 327 return getCellBroadcastChannelsConfig(subId, roamingOperator, enableAlertsMasterToggle, 328 enableEtwsAlerts, enablePresidential, enableCmasExtremeAlerts, 329 enableCmasSevereAlerts, enableCmasAmberAlerts, enableTestAlerts, 330 enableExerciseAlerts, enableOperatorDefined, enableAreaUpdateInfoAlerts, 331 enablePublicSafetyMessagesChannelAlerts, enableStateLocalTestAlerts, 332 enableEmergencyAlerts, true); 333 } 334 getCellBroadcastChannelsConfig(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)335 private List<CbConfig> getCellBroadcastChannelsConfig(int subId, @NonNull String operator, 336 boolean enableAlertsMasterToggle, boolean enableEtwsAlerts, boolean enablePresidential, 337 boolean enableCmasExtremeAlerts, boolean enableCmasSevereAlerts, 338 boolean enableCmasAmberAlerts, boolean enableTestAlerts, boolean enableExerciseAlerts, 339 boolean enableOperatorDefined, boolean enableAreaUpdateInfoAlerts, 340 boolean enablePublicSafetyMessagesChannelAlerts, boolean enableStateLocalTestAlerts, 341 boolean enableEmergencyAlerts, boolean enableGeoFencingTriggerMessage) { 342 343 if (VDBG) { 344 log("setCellBroadcastChannelsEnabled for " + subId + ", operator: " + operator); 345 log("enableAlertsMasterToggle = " + enableAlertsMasterToggle); 346 log("enableEtwsAlerts = " + enableEtwsAlerts); 347 log("enablePresidential = " + enablePresidential); 348 log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts); 349 log("enableCmasSevereAlerts = " + enableCmasSevereAlerts); 350 log("enableCmasAmberAlerts = " + enableCmasAmberAlerts); 351 log("enableTestAlerts = " + enableTestAlerts); 352 log("enableExerciseAlerts = " + enableExerciseAlerts); 353 log("enableOperatorDefinedAlerts = " + enableOperatorDefined); 354 log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts); 355 log("enablePublicSafetyMessagesChannelAlerts = " 356 + enablePublicSafetyMessagesChannelAlerts); 357 log("enableStateLocalTestAlerts = " + enableStateLocalTestAlerts); 358 log("enableEmergencyAlerts = " + enableEmergencyAlerts); 359 log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage); 360 } 361 362 List<CbConfig> cbConfigList = new ArrayList<>(); 363 boolean isEnableOnly = !TextUtils.isEmpty(operator); 364 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 365 getApplicationContext(), subId, operator); 366 /** Enable CMAS series messages. */ 367 368 // Enable/Disable Presidential messages. 369 List<CellBroadcastChannelRange> ranges = channelManager.getCellBroadcastChannelRanges( 370 R.array.cmas_presidential_alerts_channels_range_strings); 371 for (CellBroadcastChannelRange range : ranges) { 372 boolean enable = range.mAlwaysOn || enablePresidential; 373 if (enable || !isEnableOnly) { 374 cbConfigList.add( 375 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 376 } 377 } 378 379 // Enable/Disable CMAS extreme messages. 380 ranges = channelManager.getCellBroadcastChannelRanges( 381 R.array.cmas_alert_extreme_channels_range_strings); 382 for (CellBroadcastChannelRange range : ranges) { 383 boolean enable = range.mAlwaysOn || enableCmasExtremeAlerts; 384 if (enable || !isEnableOnly) { 385 cbConfigList.add( 386 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 387 } 388 } 389 390 // Enable/Disable CMAS severe messages. 391 ranges = channelManager.getCellBroadcastChannelRanges( 392 R.array.cmas_alerts_severe_range_strings); 393 for (CellBroadcastChannelRange range : ranges) { 394 boolean enable = range.mAlwaysOn || enableCmasSevereAlerts; 395 if (enable || !isEnableOnly) { 396 cbConfigList.add( 397 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 398 } 399 } 400 401 // Enable/Disable CMAS amber alert messages. 402 ranges = channelManager.getCellBroadcastChannelRanges( 403 R.array.cmas_amber_alerts_channels_range_strings); 404 for (CellBroadcastChannelRange range : ranges) { 405 boolean enable = range.mAlwaysOn || enableCmasAmberAlerts; 406 if (enable || !isEnableOnly) { 407 cbConfigList.add( 408 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 409 } 410 } 411 412 // Enable/Disable test messages. 413 ranges = channelManager.getCellBroadcastChannelRanges( 414 R.array.required_monthly_test_range_strings); 415 for (CellBroadcastChannelRange range : ranges) { 416 boolean enable = range.mAlwaysOn || enableTestAlerts; 417 if (enable || !isEnableOnly) { 418 cbConfigList.add( 419 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 420 } 421 } 422 423 // Enable/Disable exercise test messages. 424 // This could either controlled by main test toggle or separate exercise test toggle. 425 ranges = channelManager.getCellBroadcastChannelRanges(R.array.exercise_alert_range_strings); 426 for (CellBroadcastChannelRange range : ranges) { 427 boolean enable = range.mAlwaysOn || (enableTestAlerts || enableExerciseAlerts); 428 if (enable || !isEnableOnly) { 429 cbConfigList.add( 430 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 431 } 432 } 433 434 // Enable/Disable operator defined test messages. 435 // This could either controlled by main test toggle or separate operator defined test toggle 436 ranges = channelManager.getCellBroadcastChannelRanges( 437 R.array.operator_defined_alert_range_strings); 438 for (CellBroadcastChannelRange range : ranges) { 439 boolean enable = range.mAlwaysOn || (enableTestAlerts || enableOperatorDefined); 440 if (enable || !isEnableOnly) { 441 cbConfigList.add( 442 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 443 } 444 } 445 446 // Enable/Disable GSM ETWS messages. 447 ranges = channelManager.getCellBroadcastChannelRanges(R.array.etws_alerts_range_strings); 448 for (CellBroadcastChannelRange range : ranges) { 449 boolean enable = range.mAlwaysOn || enableEtwsAlerts; 450 if (enable || !isEnableOnly) { 451 cbConfigList.add( 452 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 453 } 454 } 455 456 // Enable/Disable GSM ETWS test messages. 457 ranges = channelManager.getCellBroadcastChannelRanges( 458 R.array.etws_test_alerts_range_strings); 459 for (CellBroadcastChannelRange range : ranges) { 460 boolean enable = range.mAlwaysOn || enableTestAlerts; 461 if (enable || !isEnableOnly) { 462 cbConfigList.add( 463 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 464 } 465 } 466 467 // Enable/Disable GSM public safety messages. 468 ranges = channelManager.getCellBroadcastChannelRanges( 469 R.array.public_safety_messages_channels_range_strings); 470 for (CellBroadcastChannelRange range : ranges) { 471 boolean enable = range.mAlwaysOn || enablePublicSafetyMessagesChannelAlerts; 472 if (enable || !isEnableOnly) { 473 cbConfigList.add( 474 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 475 } 476 } 477 478 // Enable/Disable GSM state/local test alerts. 479 ranges = channelManager.getCellBroadcastChannelRanges( 480 R.array.state_local_test_alert_range_strings); 481 for (CellBroadcastChannelRange range : ranges) { 482 boolean enable = range.mAlwaysOn || enableStateLocalTestAlerts; 483 if (enable || !isEnableOnly) { 484 cbConfigList.add( 485 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 486 } 487 } 488 489 // Enable/Disable GSM geo-fencing trigger messages. 490 ranges = channelManager.getCellBroadcastChannelRanges( 491 R.array.geo_fencing_trigger_messages_range_strings); 492 for (CellBroadcastChannelRange range : ranges) { 493 boolean enable = range.mAlwaysOn || enableGeoFencingTriggerMessage; 494 if (enable || !isEnableOnly) { 495 cbConfigList.add( 496 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 497 } 498 } 499 500 // Enable non-CMAS series messages. 501 ranges = channelManager.getCellBroadcastChannelRanges( 502 R.array.emergency_alerts_channels_range_strings); 503 for (CellBroadcastChannelRange range : ranges) { 504 boolean enable = range.mAlwaysOn || enableEmergencyAlerts; 505 if (enable || !isEnableOnly) { 506 cbConfigList.add( 507 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 508 } 509 } 510 511 // Enable/Disable additional channels based on carrier specific requirement. 512 List<CellBroadcastChannelRange> additionChannelRanges = 513 channelManager.getCellBroadcastChannelRanges( 514 R.array.additional_cbs_channels_strings); 515 516 for (CellBroadcastChannelRange range : additionChannelRanges) { 517 boolean enableAlerts; 518 switch (range.mAlertType) { 519 case AREA: 520 enableAlerts = enableAreaUpdateInfoAlerts; 521 break; 522 case TEST: 523 enableAlerts = enableTestAlerts; 524 break; 525 default: 526 enableAlerts = enableAlertsMasterToggle; 527 } 528 boolean enable = range.mAlwaysOn || enableAlerts; 529 if (enable || !isEnableOnly) { 530 cbConfigList.add( 531 new CbConfig(range.mStartId, range.mEndId, range.mRanType, enable)); 532 } 533 } 534 return cbConfigList; 535 } 536 537 /** 538 * Enable/disable cell broadcast with messages id range 539 * 540 * @param subId Subscription index 541 * @param ranges Cell broadcast id ranges 542 */ setCellBroadcastRange(int subId, List<CbConfig> ranges)543 private void setCellBroadcastRange(int subId, List<CbConfig> ranges) { 544 SmsManager manager; 545 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 546 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 547 } else { 548 manager = SmsManager.getDefault(); 549 } 550 List<CellBroadcastIdRange> channelIdRanges = new ArrayList<>(); 551 552 if (ranges != null) { 553 for (CbConfig range : ranges) { 554 boolean enable = range.mEnable; 555 if (SdkLevel.isAtLeastU()) { 556 if (VDBG) { 557 log("enableCellBroadcastRange[" + range.mStartId + "-" 558 + range.mEndId + "], type:" + range.mRanType 559 + ", enable:" + enable); 560 } 561 if (enable) { 562 mChannelRangeForMetric.add(new Pair(range.mStartId, range.mEndId)); 563 } 564 CellBroadcastIdRange cbRange = new CellBroadcastIdRange(range.mStartId, 565 range.mEndId, range.mRanType, enable); 566 channelIdRanges.add(cbRange); 567 } else { 568 if (enable) { 569 if (VDBG) { 570 log("enableCellBroadcastRange[" + range.mStartId + "-" 571 + range.mEndId + "], type:" + range.mRanType); 572 } 573 mChannelRangeForMetric.add(new Pair(range.mStartId, range.mEndId)); 574 manager.enableCellBroadcastRange(range.mStartId, range.mEndId, 575 range.mRanType); 576 } else { 577 if (VDBG) { 578 log("disableCellBroadcastRange[" + range.mStartId + "-" 579 + range.mEndId + "], type:" + range.mRanType); 580 } 581 manager.disableCellBroadcastRange(range.mStartId, range.mEndId, 582 range.mRanType); 583 } 584 } 585 } 586 if (SdkLevel.isAtLeastU()) { 587 TelephonyManager tm = getApplicationContext().getSystemService( 588 TelephonyManager.class).createForSubscriptionId(subId); 589 try { 590 tm.setCellBroadcastIdRanges(channelIdRanges, Runnable::run, result -> { 591 if (result != TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS) { 592 Log.e(TAG, "fails to setCellBroadcastRanges, result = " + result); 593 } 594 }); 595 } catch (RuntimeException e) { 596 Log.e(TAG, "fails to setCellBroadcastRanges"); 597 } 598 } 599 } 600 } 601 602 /** 603 * Merge the conflicted CbConfig in the list as needed 604 * @param inputRanges input config lists 605 * @return the list of CbConfig without conflict 606 */ 607 @VisibleForTesting mergeConfigAsNeeded(List<CbConfig> inputRanges)608 public static List<CbConfig> mergeConfigAsNeeded(List<CbConfig> inputRanges) { 609 inputRanges.sort((r1, r2) -> r1.mRanType != r2.mRanType ? r1.mRanType - r2.mRanType 610 : (r1.mStartId != r2.mStartId ? r1.mStartId - r2.mStartId 611 : r2.mEndId - r1.mEndId)); 612 final List<CbConfig> ranges = new ArrayList<>(); 613 inputRanges.forEach(r -> { 614 if (ranges.isEmpty() || ranges.get(ranges.size() - 1).mRanType != r.mRanType 615 || ranges.get(ranges.size() - 1).mEndId < r.mStartId) { 616 ranges.add(new CbConfig(r.mStartId, r.mEndId, r.mRanType, r.mEnable)); 617 } else { 618 CbConfig range = ranges.get(ranges.size() - 1); 619 if (range.mEnable == r.mEnable) { 620 if (r.mEndId > range.mEndId) { 621 ranges.set(ranges.size() - 1, new CbConfig( 622 range.mStartId, r.mEndId, range.mRanType, range.mEnable)); 623 } 624 } else if (!range.mEnable) { 625 if (range.mStartId < r.mStartId) { 626 if (range.mEndId <= r.mEndId) { 627 ranges.set(ranges.size() - 1, new CbConfig(range.mStartId, 628 r.mStartId - 1, range.mRanType, false)); 629 ranges.add(new CbConfig(r.mStartId, r.mEndId, r.mRanType, true)); 630 } else { 631 ranges.set(ranges.size() - 1, new CbConfig(range.mStartId, 632 r.mStartId - 1, range.mRanType, false)); 633 ranges.add(new CbConfig(r.mStartId, r.mEndId, r.mRanType, true)); 634 ranges.add(new CbConfig(r.mEndId + 1, range.mEndId, 635 range.mRanType, false)); 636 } 637 } else { 638 if (range.mEndId <= r.mEndId) { 639 ranges.set(ranges.size() - 1, new CbConfig(r.mStartId, 640 r.mEndId, range.mRanType, true)); 641 } else if (range.mStartId <= r.mEndId) { 642 ranges.set(ranges.size() - 1, new CbConfig(r.mStartId, 643 r.mEndId, range.mRanType, true)); 644 ranges.add(new CbConfig(r.mEndId + 1, range.mEndId, 645 r.mRanType, false)); 646 } 647 } 648 } else { 649 if (range.mEndId < r.mEndId) { 650 ranges.add(new CbConfig(range.mEndId + 1, r.mEndId, r.mRanType, false)); 651 } 652 } 653 } 654 }); 655 return ranges; 656 } 657 658 /** 659 * Get resource according to the operator or subId 660 * 661 * @param subId Subscription index 662 * @param operator Operator numeric, the resource will be retrieved by it if it is no null, 663 * otherwise, by the sub id. 664 */ 665 @VisibleForTesting getResources(int subId, String operator)666 public Resources getResources(int subId, String operator) { 667 if (operator == null) { 668 return CellBroadcastSettings.getResources(this, subId); 669 } 670 return CellBroadcastSettings.getResourcesByOperator(this, subId, operator); 671 } 672 broadcastSetChannelsIsDone(int subId)673 private void broadcastSetChannelsIsDone(int subId) { 674 if (!isMockModemRunning()) { 675 return; 676 } 677 Intent intent = new Intent(ACTION_SET_CHANNELS_DONE); 678 intent.putExtra("sub_id", subId); 679 sendBroadcast(intent, Manifest.permission.READ_CELL_BROADCASTS); 680 Log.d(TAG, "broadcastSetChannelsIsDone subId = " + subId); 681 } 682 isMasterToggleEnabled()683 private boolean isMasterToggleEnabled() { 684 return PreferenceManager.getDefaultSharedPreferences(this).getBoolean( 685 CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true); 686 } 687 688 /** 689 * Check if mockmodem is running 690 * @return true if mockmodem service is running instead of real modem 691 */ 692 @VisibleForTesting isMockModemRunning()693 public boolean isMockModemRunning() { 694 return CellBroadcastReceiver.isMockModemBinded(); 695 } 696 log(String msg)697 private static void log(String msg) { 698 Log.d(TAG, msg); 699 } 700 } 701