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 21 import android.app.IntentService; 22 import android.app.Notification; 23 import android.app.NotificationManager; 24 import android.app.PendingIntent; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.content.res.Resources; 29 import android.preference.PreferenceManager; 30 import android.telephony.SmsManager; 31 import android.telephony.SubscriptionInfo; 32 import android.telephony.SubscriptionManager; 33 import android.text.TextUtils; 34 import android.util.Log; 35 36 import androidx.annotation.NonNull; 37 38 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange; 39 import com.android.internal.annotations.VisibleForTesting; 40 import com.android.modules.utils.build.SdkLevel; 41 42 import java.lang.reflect.Method; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.List; 46 47 /** 48 * This service manages enabling and disabling ranges of message identifiers 49 * that the radio should listen for. It operates independently of the other 50 * services and runs at boot time and after exiting airplane mode. 51 * 52 * Note that the entire range of emergency channels is enabled. Test messages 53 * and lower priority broadcasts are filtered out in CellBroadcastAlertService 54 * if the user has not enabled them in settings. 55 * 56 * TODO: add notification to re-enable channels after a radio reset. 57 */ 58 public class CellBroadcastConfigService extends IntentService { 59 private static final String TAG = "CellBroadcastConfigService"; 60 61 @VisibleForTesting 62 public static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS"; 63 public static final String ACTION_UPDATE_SETTINGS_FOR_CARRIER = "UPDATE_SETTINGS_FOR_CARRIER"; 64 CellBroadcastConfigService()65 public CellBroadcastConfigService() { 66 super(TAG); // use class name for worker thread name 67 } 68 69 @Override onHandleIntent(Intent intent)70 protected void onHandleIntent(Intent intent) { 71 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 72 try { 73 SubscriptionManager subManager = (SubscriptionManager) getApplicationContext() 74 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 75 76 if (subManager != null) { 77 // Retrieve all the active subscription indice and enable cell broadcast 78 // messages on all subs. The duplication detection will be done at the 79 // frameworks. 80 int[] subIds = getActiveSubIdList(subManager); 81 if (subIds.length != 0) { 82 for (int subId : subIds) { 83 log("Enable CellBroadcast on sub " + subId); 84 enableCellBroadcastChannels(subId); 85 enableCellBroadcastRoamingChannelsAsNeeded(subId); 86 } 87 } else { 88 // For no sim scenario. 89 enableCellBroadcastChannels(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 90 enableCellBroadcastRoamingChannelsAsNeeded( 91 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 92 } 93 } 94 } catch (Exception ex) { 95 Log.e(TAG, "exception enabling cell broadcast channels", ex); 96 } 97 } else if (ACTION_UPDATE_SETTINGS_FOR_CARRIER.equals(intent.getAction())) { 98 Context c = getApplicationContext(); 99 if (CellBroadcastSettings.hasAnyPreferenceChanged(c)) { 100 Log.d(TAG, "Preference has changed from user set, posting notification."); 101 102 CellBroadcastAlertService.createNotificationChannels(c); 103 Intent settingsIntent = new Intent(c, CellBroadcastSettings.class); 104 PendingIntent pi = PendingIntent.getActivity(c, 105 CellBroadcastAlertService.SETTINGS_CHANGED_NOTIFICATION_ID, settingsIntent, 106 PendingIntent.FLAG_ONE_SHOT 107 | PendingIntent.FLAG_UPDATE_CURRENT 108 | PendingIntent.FLAG_IMMUTABLE); 109 110 Notification.Builder builder = new Notification.Builder(c, 111 CellBroadcastAlertService.NOTIFICATION_CHANNEL_SETTINGS_UPDATES) 112 .setCategory(Notification.CATEGORY_SYSTEM) 113 .setContentTitle(c.getString(R.string.notification_cb_settings_changed_title)) 114 .setContentText(c.getString(R.string.notification_cb_settings_changed_text)) 115 .setSmallIcon(R.drawable.ic_settings_gear_outline_24dp) 116 .setContentIntent(pi) 117 .setAutoCancel(true); 118 NotificationManager notificationManager = c.getSystemService( 119 NotificationManager.class); 120 notificationManager.notify( 121 CellBroadcastAlertService.SETTINGS_CHANGED_NOTIFICATION_ID, 122 builder.build()); 123 } 124 Log.e(TAG, "Reset all preferences"); 125 CellBroadcastSettings.resetAllPreferences(getApplicationContext()); 126 } 127 } 128 129 @NonNull getActiveSubIdList(SubscriptionManager subMgr)130 private int[] getActiveSubIdList(SubscriptionManager subMgr) { 131 List<SubscriptionInfo> subInfos = subMgr.getActiveSubscriptionInfoList(); 132 int size = subInfos != null ? subInfos.size() : 0; 133 int[] subIds = new int[size]; 134 for (int i = 0; i < size; i++) { 135 subIds[i] = subInfos.get(i).getSubscriptionId(); 136 } 137 return subIds; 138 } 139 resetCellBroadcastChannels(int subId)140 private void resetCellBroadcastChannels(int subId) { 141 SmsManager manager; 142 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 143 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 144 } else { 145 manager = SmsManager.getDefault(); 146 } 147 // SmsManager.resetAllCellBroadcastRanges is a new @SystemAPI in S. We need to support 148 // backward compatibility as the module need to run on R build as well. 149 if (SdkLevel.isAtLeastS()) { 150 manager.resetAllCellBroadcastRanges(); 151 } else { 152 try { 153 Method method = SmsManager.class.getDeclaredMethod("resetAllCellBroadcastRanges"); 154 method.invoke(manager); 155 } catch (Exception e) { 156 log("Can't reset cell broadcast ranges. e=" + e); 157 } 158 } 159 } 160 161 /** 162 * Enable cell broadcast messages channels. Messages can be only received on the 163 * enabled channels. 164 * 165 * @param subId Subscription index 166 */ 167 @VisibleForTesting enableCellBroadcastChannels(int subId)168 public void enableCellBroadcastChannels(int subId) { 169 resetCellBroadcastChannels(subId); 170 171 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 172 Resources res = getResources(subId, null); 173 174 // boolean for each user preference checkbox, true for checked, false for unchecked 175 // Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts 176 // except for always-on alerts e.g, presidential. i.e. to receive CMAS severe alerts, both 177 // enableAlertsMasterToggle AND enableCmasSevereAlerts must be true. 178 boolean enableAlertsMasterToggle = prefs.getBoolean( 179 CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true); 180 181 boolean enableEtwsAlerts = enableAlertsMasterToggle; 182 183 // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless 184 // user's preference 185 boolean enablePresidential = true; 186 187 boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && prefs.getBoolean( 188 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); 189 190 boolean enableCmasSevereAlerts = enableAlertsMasterToggle && prefs.getBoolean( 191 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); 192 193 boolean enableCmasAmberAlerts = enableAlertsMasterToggle && prefs.getBoolean( 194 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); 195 196 boolean enableTestAlerts = enableAlertsMasterToggle 197 && CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext()) 198 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false); 199 200 boolean enableExerciseAlerts = enableAlertsMasterToggle 201 && res.getBoolean(R.bool.show_separate_exercise_settings) 202 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_EXERCISE_ALERTS, false); 203 204 boolean enableOperatorDefined = enableAlertsMasterToggle 205 && res.getBoolean(R.bool.show_separate_operator_defined_settings) 206 && prefs.getBoolean(CellBroadcastSettings.KEY_OPERATOR_DEFINED_ALERTS, false); 207 208 boolean enableAreaUpdateInfoAlerts = res.getBoolean( 209 R.bool.config_showAreaUpdateInfoSettings) 210 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS, 211 false); 212 213 boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle 214 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES, 215 true); 216 boolean enableStateLocalTestAlerts = enableAlertsMasterToggle 217 && (prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS, 218 false) 219 || (!res.getBoolean(R.bool.show_state_local_test_settings) 220 && res.getBoolean(R.bool.state_local_test_alerts_enabled_default))); 221 222 boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean( 223 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); 224 225 setCellBroadcastChannelsEnabled(subId, null, enableAlertsMasterToggle, enableEtwsAlerts, 226 enablePresidential, enableCmasExtremeAlerts, enableCmasSevereAlerts, 227 enableCmasAmberAlerts, enableTestAlerts, enableExerciseAlerts, 228 enableOperatorDefined, enableAreaUpdateInfoAlerts, 229 enablePublicSafetyMessagesChannelAlerts, enableStateLocalTestAlerts, 230 enableEmergencyAlerts, true); 231 } 232 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)233 private void setCellBroadcastChannelsEnabled(int subId, @NonNull String operator, 234 boolean enableAlertsMasterToggle, boolean enableEtwsAlerts, boolean enablePresidential, 235 boolean enableCmasExtremeAlerts, boolean enableCmasSevereAlerts, 236 boolean enableCmasAmberAlerts, boolean enableTestAlerts, boolean enableExerciseAlerts, 237 boolean enableOperatorDefined, boolean enableAreaUpdateInfoAlerts, 238 boolean enablePublicSafetyMessagesChannelAlerts, boolean enableStateLocalTestAlerts, 239 boolean enableEmergencyAlerts, boolean enableGeoFencingTriggerMessage) { 240 241 if (VDBG) { 242 log("setCellBroadcastChannelsEnabled for " + subId + ", operator: " + operator); 243 log("enableAlertsMasterToggle = " + enableAlertsMasterToggle); 244 log("enableEtwsAlerts = " + enableEtwsAlerts); 245 log("enablePresidential = " + enablePresidential); 246 log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts); 247 log("enableCmasSevereAlerts = " + enableCmasSevereAlerts); 248 log("enableCmasAmberAlerts = " + enableCmasAmberAlerts); 249 log("enableTestAlerts = " + enableTestAlerts); 250 log("enableExerciseAlerts = " + enableExerciseAlerts); 251 log("enableOperatorDefinedAlerts = " + enableOperatorDefined); 252 log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts); 253 log("enablePublicSafetyMessagesChannelAlerts = " 254 + enablePublicSafetyMessagesChannelAlerts); 255 log("enableStateLocalTestAlerts = " + enableStateLocalTestAlerts); 256 log("enableEmergencyAlerts = " + enableEmergencyAlerts); 257 log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage); 258 } 259 260 boolean isEnableOnly = !TextUtils.isEmpty(operator); 261 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 262 getApplicationContext(), subId, operator); 263 264 /** Enable CMAS series messages. */ 265 266 // Enable/Disable Presidential messages. 267 setCellBroadcastRange(subId, isEnableOnly, enablePresidential, 268 channelManager.getCellBroadcastChannelRanges( 269 R.array.cmas_presidential_alerts_channels_range_strings)); 270 271 // Enable/Disable CMAS extreme messages. 272 setCellBroadcastRange(subId, isEnableOnly, enableCmasExtremeAlerts, 273 channelManager.getCellBroadcastChannelRanges( 274 R.array.cmas_alert_extreme_channels_range_strings)); 275 276 // Enable/Disable CMAS severe messages. 277 setCellBroadcastRange(subId, isEnableOnly, enableCmasSevereAlerts, 278 channelManager.getCellBroadcastChannelRanges( 279 R.array.cmas_alerts_severe_range_strings)); 280 281 // Enable/Disable CMAS amber alert messages. 282 setCellBroadcastRange(subId, isEnableOnly, enableCmasAmberAlerts, 283 channelManager.getCellBroadcastChannelRanges( 284 R.array.cmas_amber_alerts_channels_range_strings)); 285 286 // Enable/Disable test messages. 287 setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts, 288 channelManager.getCellBroadcastChannelRanges( 289 R.array.required_monthly_test_range_strings)); 290 291 // Enable/Disable exercise test messages. 292 // This could either controlled by main test toggle or separate exercise test toggle. 293 setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts || enableExerciseAlerts, 294 channelManager.getCellBroadcastChannelRanges( 295 R.array.exercise_alert_range_strings)); 296 297 // Enable/Disable operator defined test messages. 298 // This could either controlled by main test toggle or separate operator defined test toggle 299 setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts || enableOperatorDefined, 300 channelManager.getCellBroadcastChannelRanges( 301 R.array.operator_defined_alert_range_strings)); 302 303 // Enable/Disable GSM ETWS messages. 304 setCellBroadcastRange(subId, isEnableOnly, enableEtwsAlerts, 305 channelManager.getCellBroadcastChannelRanges( 306 R.array.etws_alerts_range_strings)); 307 308 // Enable/Disable GSM ETWS test messages. 309 setCellBroadcastRange(subId, isEnableOnly, enableTestAlerts, 310 channelManager.getCellBroadcastChannelRanges( 311 R.array.etws_test_alerts_range_strings)); 312 313 // Enable/Disable GSM public safety messages. 314 setCellBroadcastRange(subId, isEnableOnly, enablePublicSafetyMessagesChannelAlerts, 315 channelManager.getCellBroadcastChannelRanges( 316 R.array.public_safety_messages_channels_range_strings)); 317 318 // Enable/Disable GSM state/local test alerts. 319 setCellBroadcastRange(subId, isEnableOnly, enableStateLocalTestAlerts, 320 channelManager.getCellBroadcastChannelRanges( 321 R.array.state_local_test_alert_range_strings)); 322 323 // Enable/Disable GSM geo-fencing trigger messages. 324 setCellBroadcastRange(subId, isEnableOnly, enableGeoFencingTriggerMessage, 325 channelManager.getCellBroadcastChannelRanges( 326 R.array.geo_fencing_trigger_messages_range_strings)); 327 328 // Enable non-CMAS series messages. 329 setCellBroadcastRange(subId, isEnableOnly, enableEmergencyAlerts, 330 channelManager.getCellBroadcastChannelRanges( 331 R.array.emergency_alerts_channels_range_strings)); 332 333 // Enable/Disable additional channels based on carrier specific requirement. 334 List<CellBroadcastChannelRange> ranges = 335 channelManager.getCellBroadcastChannelRanges( 336 R.array.additional_cbs_channels_strings); 337 338 for (CellBroadcastChannelRange range: ranges) { 339 boolean enableAlerts; 340 switch (range.mAlertType) { 341 case AREA: 342 enableAlerts = enableAreaUpdateInfoAlerts; 343 break; 344 case TEST: 345 enableAlerts = enableTestAlerts; 346 break; 347 default: 348 enableAlerts = enableAlertsMasterToggle; 349 } 350 setCellBroadcastRange(subId, isEnableOnly, enableAlerts, 351 new ArrayList<>(Arrays.asList(range))); 352 } 353 } 354 355 /** 356 * Enable cell broadcast messages channels. Messages can be only received on the 357 * enabled channels. 358 * 359 * @param subId Subscription index 360 */ 361 @VisibleForTesting enableCellBroadcastRoamingChannelsAsNeeded(int subId)362 public void enableCellBroadcastRoamingChannelsAsNeeded(int subId) { 363 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 364 subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 365 } 366 367 String roamingOperator = CellBroadcastReceiver.getRoamingOperatorSupported(this); 368 if (roamingOperator.isEmpty()) { 369 return; 370 } 371 372 log("enableCellBroadcastRoamingChannels for roaming network:" + roamingOperator); 373 Resources res = getResources(subId, roamingOperator); 374 375 // Get default config for roaming network as the settings are based on sim 376 boolean enablePresidential = true; 377 378 boolean enableAlertsMasterToggle = res.getBoolean(R.bool.master_toggle_enabled_default); 379 380 boolean enableEtwsAlerts = enableAlertsMasterToggle; 381 382 boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && res.getBoolean( 383 R.bool.extreme_threat_alerts_enabled_default); 384 385 boolean enableCmasSevereAlerts = enableAlertsMasterToggle && res.getBoolean( 386 R.bool.severe_threat_alerts_enabled_default); 387 388 boolean enableCmasAmberAlerts = enableAlertsMasterToggle && res.getBoolean( 389 R.bool.amber_alerts_enabled_default); 390 391 boolean enableTestAlerts = enableAlertsMasterToggle && CellBroadcastSettings 392 .isTestAlertsToggleVisible(getApplicationContext(), roamingOperator) 393 && res.getBoolean(R.bool.test_alerts_enabled_default); 394 395 boolean enableExerciseAlerts = enableAlertsMasterToggle 396 && res.getBoolean(R.bool.show_separate_exercise_settings) 397 && res.getBoolean(R.bool.test_exercise_alerts_enabled_default); 398 399 boolean enableOperatorDefined = enableAlertsMasterToggle 400 && res.getBoolean(R.bool.show_separate_operator_defined_settings) 401 && res.getBoolean(R.bool.test_operator_defined_alerts_enabled_default); 402 403 boolean enableAreaUpdateInfoAlerts = res.getBoolean( 404 R.bool.config_showAreaUpdateInfoSettings) 405 && res.getBoolean(R.bool.area_update_info_alerts_enabled_default); 406 407 boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle 408 && res.getBoolean(R.bool.public_safety_messages_enabled_default); 409 boolean enableStateLocalTestAlerts = enableAlertsMasterToggle 410 && res.getBoolean(R.bool.state_local_test_alerts_enabled_default); 411 412 boolean enableEmergencyAlerts = enableAlertsMasterToggle && res.getBoolean( 413 R.bool.emergency_alerts_enabled_default); 414 415 setCellBroadcastChannelsEnabled(subId, roamingOperator, enableAlertsMasterToggle, 416 enableEtwsAlerts, enablePresidential, enableCmasExtremeAlerts, 417 enableCmasSevereAlerts, enableCmasAmberAlerts, enableTestAlerts, 418 enableExerciseAlerts, enableOperatorDefined, enableAreaUpdateInfoAlerts, 419 enablePublicSafetyMessagesChannelAlerts, enableStateLocalTestAlerts, 420 enableEmergencyAlerts, true); 421 } 422 423 /** 424 * Enable/disable cell broadcast with messages id range 425 * @param subId Subscription index 426 * @param isEnableOnly, True for enabling channel only for roaming network 427 * @param enable True for enabling cell broadcast with id range, otherwise for disabling 428 * @param ranges Cell broadcast id ranges 429 */ setCellBroadcastRange(int subId, boolean isEnableOnly, boolean enable, List<CellBroadcastChannelRange> ranges)430 private void setCellBroadcastRange(int subId, boolean isEnableOnly, 431 boolean enable, List<CellBroadcastChannelRange> ranges) { 432 SmsManager manager; 433 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 434 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 435 } else { 436 manager = SmsManager.getDefault(); 437 } 438 439 if (ranges != null) { 440 for (CellBroadcastChannelRange range: ranges) { 441 if (range.mAlwaysOn) { 442 log("mAlwaysOn is set to true, enable the range: " + range.mStartId 443 + ":" + range.mEndId); 444 enable = true; 445 } 446 447 if (enable) { 448 if (VDBG) { 449 log("enableCellBroadcastRange[" + range.mStartId + "-" + range.mEndId 450 + "], type:" + range.mRanType); 451 } 452 manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType); 453 } else if (!isEnableOnly) { 454 if (VDBG) { 455 log("disableCellBroadcastRange[" + range.mStartId + "-" + range.mEndId 456 + "], type:" + range.mRanType); 457 } 458 manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType); 459 } 460 } 461 } 462 } 463 464 465 /** 466 * Get resource according to the operator or subId 467 * @param subId Subscription index 468 * @param operator Operator numeric, the resource will be retrieved by it if it is no null, 469 * otherwise, by the sub id. 470 */ 471 @VisibleForTesting getResources(int subId, String operator)472 public Resources getResources(int subId, String operator) { 473 if (operator == null) { 474 return CellBroadcastSettings.getResources(this, subId); 475 } 476 return CellBroadcastSettings.getResourcesByOperator(this, subId, operator); 477 } 478 log(String msg)479 private static void log(String msg) { 480 Log.d(TAG, msg); 481 } 482 } 483