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 android.app.IntentService; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.SharedPreferences; 23 import android.content.res.Resources; 24 import android.os.SystemProperties; 25 import android.preference.PreferenceManager; 26 import android.telephony.CellBroadcastMessage; 27 import android.telephony.SmsManager; 28 import android.telephony.TelephonyManager; 29 import android.text.TextUtils; 30 import android.util.Log; 31 32 import com.android.internal.telephony.cdma.sms.SmsEnvelope; 33 import com.android.internal.telephony.gsm.SmsCbConstants; 34 35 import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.DBG; 36 37 /** 38 * This service manages enabling and disabling ranges of message identifiers 39 * that the radio should listen for. It operates independently of the other 40 * services and runs at boot time and after exiting airplane mode. 41 * 42 * Note that the entire range of emergency channels is enabled. Test messages 43 * and lower priority broadcasts are filtered out in CellBroadcastAlertService 44 * if the user has not enabled them in settings. 45 * 46 * TODO: add notification to re-enable channels after a radio reset. 47 */ 48 public class CellBroadcastConfigService extends IntentService { 49 private static final String TAG = "CellBroadcastConfigService"; 50 51 static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS"; 52 53 static final String EMERGENCY_BROADCAST_RANGE_GSM = 54 "ro.cb.gsm.emergencyids"; 55 56 public CellBroadcastConfigService() { 57 super(TAG); // use class name for worker thread name 58 } 59 60 private static void setChannelRange(SmsManager manager, String ranges, boolean enable) { 61 if (DBG)log("setChannelRange: " + ranges); 62 63 try { 64 for (String channelRange : ranges.split(",")) { 65 int dashIndex = channelRange.indexOf('-'); 66 if (dashIndex != -1) { 67 int startId = Integer.decode(channelRange.substring(0, dashIndex).trim()); 68 int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim()); 69 if (enable) { 70 if (DBG) log("enabling emergency IDs " + startId + '-' + endId); 71 manager.enableCellBroadcastRange(startId, endId); 72 } else { 73 if (DBG) log("disabling emergency IDs " + startId + '-' + endId); 74 manager.disableCellBroadcastRange(startId, endId); 75 } 76 } else { 77 int messageId = Integer.decode(channelRange.trim()); 78 if (enable) { 79 if (DBG) log("enabling emergency message ID " + messageId); 80 manager.enableCellBroadcast(messageId); 81 } else { 82 if (DBG) log("disabling emergency message ID " + messageId); 83 manager.disableCellBroadcast(messageId); 84 } 85 } 86 } 87 } catch (NumberFormatException e) { 88 Log.e(TAG, "Number Format Exception parsing emergency channel range", e); 89 } 90 91 // Make sure CMAS Presidential is enabled (See 3GPP TS 22.268 Section 6.2). 92 if (DBG) log("setChannelRange: enabling CMAS Presidential"); 93 if (CellBroadcastReceiver.phoneIsCdma()) { 94 manager.enableCellBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT); 95 } else { 96 manager.enableCellBroadcast(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL); 97 // register Taiwan PWS 4383 also, by default 98 manager.enableCellBroadcast(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE); 99 } 100 } 101 102 /** 103 * Returns true if this is a standard or operator-defined emergency alert message. 104 * This includes all ETWS and CMAS alerts, except for AMBER alerts. 105 * @param message the message to test 106 * @return true if the message is an emergency alert; false otherwise 107 */ 108 static boolean isEmergencyAlertMessage(CellBroadcastMessage message) { 109 if (message.isEmergencyAlertMessage()) { 110 return true; 111 } 112 113 // Check for system property defining the emergency channel ranges to enable 114 String emergencyIdRange = (CellBroadcastReceiver.phoneIsCdma()) ? 115 "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); 116 117 if (TextUtils.isEmpty(emergencyIdRange)) { 118 return false; 119 } 120 try { 121 int messageId = message.getServiceCategory(); 122 for (String channelRange : emergencyIdRange.split(",")) { 123 int dashIndex = channelRange.indexOf('-'); 124 if (dashIndex != -1) { 125 int startId = Integer.decode(channelRange.substring(0, dashIndex).trim()); 126 int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim()); 127 if (messageId >= startId && messageId <= endId) { 128 return true; 129 } 130 } else { 131 int emergencyMessageId = Integer.decode(channelRange.trim()); 132 if (emergencyMessageId == messageId) { 133 return true; 134 } 135 } 136 } 137 } catch (NumberFormatException e) { 138 Log.e(TAG, "Number Format Exception parsing emergency channel range", e); 139 } 140 return false; 141 } 142 143 @Override 144 protected void onHandleIntent(Intent intent) { 145 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 146 try { 147 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 148 Resources res = getResources(); 149 150 // boolean for each user preference checkbox, true for checked, false for unchecked 151 // Note: If enableEmergencyAlerts is false, it disables ALL emergency broadcasts 152 // except for cmas presidential. i.e. to receive cmas severe alerts, both 153 // enableEmergencyAlerts AND enableCmasSevereAlerts must be true. 154 boolean enableEmergencyAlerts = prefs.getBoolean( 155 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); 156 157 TelephonyManager tm = (TelephonyManager) getSystemService( 158 Context.TELEPHONY_SERVICE); 159 160 boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) || 161 "br".equals(tm.getSimCountryIso()); 162 163 boolean enableChannel50Alerts = enableChannel50Support && 164 prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_50_ALERTS, true); 165 166 // Note: ETWS is for 3GPP only 167 boolean enableEtwsTestAlerts = prefs.getBoolean( 168 CellBroadcastSettings.KEY_ENABLE_ETWS_TEST_ALERTS, false); 169 170 boolean enableCmasExtremeAlerts = prefs.getBoolean( 171 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); 172 173 boolean enableCmasSevereAlerts = prefs.getBoolean( 174 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); 175 176 boolean enableCmasAmberAlerts = prefs.getBoolean( 177 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); 178 179 boolean enableCmasTestAlerts = prefs.getBoolean( 180 CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, false); 181 182 // set up broadcast ID ranges to be used for each category 183 int cmasExtremeStart = 184 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED; 185 int cmasExtremeEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY; 186 int cmasSevereStart = 187 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED; 188 int cmasSevereEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY; 189 int cmasAmber = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY; 190 int cmasTestStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST; 191 int cmasTestEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE; 192 int cmasPresident = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL; 193 int cmasTaiwanPWS = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE; 194 195 // set to CDMA broadcast ID rage if phone is in CDMA mode. 196 boolean isCdma = CellBroadcastReceiver.phoneIsCdma(); 197 if (isCdma) { 198 cmasExtremeStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT; 199 cmasExtremeEnd = cmasExtremeStart; 200 cmasSevereStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT; 201 cmasSevereEnd = cmasSevereStart; 202 cmasAmber = SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY; 203 cmasTestStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE; 204 cmasTestEnd = cmasTestStart; 205 cmasPresident = SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT; 206 } 207 208 SmsManager manager = SmsManager.getDefault(); 209 // Check for system property defining the emergency channel ranges to enable 210 String emergencyIdRange = isCdma ? 211 "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); 212 if (enableEmergencyAlerts) { 213 if (DBG) log("enabling emergency cell broadcast channels"); 214 if (!TextUtils.isEmpty(emergencyIdRange)) { 215 setChannelRange(manager, emergencyIdRange, true); 216 } else { 217 // No emergency channel system property, enable all emergency channels 218 // that have checkbox checked 219 if (!isCdma) { 220 manager.enableCellBroadcastRange( 221 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, 222 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING); 223 if (enableEtwsTestAlerts) { 224 manager.enableCellBroadcast( 225 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 226 } 227 manager.enableCellBroadcast( 228 SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE); 229 } 230 if (enableCmasExtremeAlerts) { 231 manager.enableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 232 } 233 if (enableCmasSevereAlerts) { 234 manager.enableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 235 } 236 if (enableCmasAmberAlerts) { 237 manager.enableCellBroadcast(cmasAmber); 238 } 239 if (enableCmasTestAlerts) { 240 manager.enableCellBroadcastRange(cmasTestStart, cmasTestEnd); 241 } 242 // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2). 243 manager.enableCellBroadcast(cmasPresident); 244 if (!isCdma) { 245 // register Taiwan PWS 4383 also, by default 246 manager.enableCellBroadcast(cmasTaiwanPWS); 247 } 248 } 249 if (DBG) log("enabled emergency cell broadcast channels"); 250 } else { 251 // we may have enabled these channels previously, so try to disable them 252 if (DBG) log("disabling emergency cell broadcast channels"); 253 if (!TextUtils.isEmpty(emergencyIdRange)) { 254 setChannelRange(manager, emergencyIdRange, false); 255 } else { 256 // No emergency channel system property, disable all emergency channels 257 // except for CMAS Presidential (See 3GPP TS 22.268 Section 6.2) 258 if (!isCdma) { 259 manager.disableCellBroadcastRange( 260 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, 261 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING); 262 manager.disableCellBroadcast( 263 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 264 manager.disableCellBroadcast( 265 SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE); 266 } 267 manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 268 manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 269 manager.disableCellBroadcast(cmasAmber); 270 manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd); 271 272 // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2). 273 manager.enableCellBroadcast(cmasPresident); 274 if (!isCdma) { 275 // register Taiwan PWS 4383 also, by default 276 manager.enableCellBroadcast(cmasTaiwanPWS); 277 } 278 } 279 if (DBG) log("disabled emergency cell broadcast channels"); 280 } 281 282 if (isCdma) { 283 if (DBG) log("channel 50 is not applicable for cdma"); 284 } else if (enableChannel50Alerts) { 285 if (DBG) log("enabling cell broadcast channel 50"); 286 manager.enableCellBroadcast(50); 287 } else { 288 if (DBG) log("disabling cell broadcast channel 50"); 289 manager.disableCellBroadcast(50); 290 } 291 292 if ("il".equals(tm.getSimCountryIso()) || "il".equals(tm.getNetworkCountryIso())) { 293 if (DBG) log("enabling channels 919-928 for Israel"); 294 manager.enableCellBroadcastRange(919, 928); 295 } else { 296 if (DBG) log("disabling channels 919-928"); 297 manager.disableCellBroadcastRange(919, 928); 298 } 299 300 // Disable per user preference/checkbox. 301 // This takes care of the case where enableEmergencyAlerts is true, 302 // but check box is unchecked to receive such as cmas severe alerts. 303 if (!enableEtwsTestAlerts && !isCdma) { 304 if (DBG) Log.d(TAG, "disabling cell broadcast ETWS test messages"); 305 manager.disableCellBroadcast( 306 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 307 } 308 if (!enableCmasExtremeAlerts) { 309 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS extreme"); 310 manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 311 } 312 if (!enableCmasSevereAlerts) { 313 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS severe"); 314 manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 315 } 316 if (!enableCmasAmberAlerts) { 317 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS amber"); 318 manager.disableCellBroadcast(cmasAmber); 319 } 320 if (!enableCmasTestAlerts) { 321 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS test messages"); 322 manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd); 323 } 324 } catch (Exception ex) { 325 Log.e(TAG, "exception enabling cell broadcast channels", ex); 326 } 327 } 328 } 329 330 private static void log(String msg) { 331 Log.d(TAG, msg); 332 } 333 } 334