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