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