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