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 } 98 } 99 100 /** 101 * Returns true if this is a standard or operator-defined emergency alert message. 102 * This includes all ETWS and CMAS alerts, except for AMBER alerts. 103 * @param message the message to test 104 * @return true if the message is an emergency alert; false otherwise 105 */ 106 static boolean isEmergencyAlertMessage(CellBroadcastMessage message) { 107 if (message.isEmergencyAlertMessage()) { 108 return true; 109 } 110 111 // Check for system property defining the emergency channel ranges to enable 112 String emergencyIdRange = (CellBroadcastReceiver.phoneIsCdma()) ? 113 "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); 114 115 if (TextUtils.isEmpty(emergencyIdRange)) { 116 return false; 117 } 118 try { 119 int messageId = message.getServiceCategory(); 120 for (String channelRange : emergencyIdRange.split(",")) { 121 int dashIndex = channelRange.indexOf('-'); 122 if (dashIndex != -1) { 123 int startId = Integer.decode(channelRange.substring(0, dashIndex).trim()); 124 int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim()); 125 if (messageId >= startId && messageId <= endId) { 126 return true; 127 } 128 } else { 129 int emergencyMessageId = Integer.decode(channelRange.trim()); 130 if (emergencyMessageId == messageId) { 131 return true; 132 } 133 } 134 } 135 } catch (NumberFormatException e) { 136 Log.e(TAG, "Number Format Exception parsing emergency channel range", e); 137 } 138 return false; 139 } 140 141 @Override 142 protected void onHandleIntent(Intent intent) { 143 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 144 try { 145 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 146 Resources res = getResources(); 147 148 // boolean for each user preference checkbox, true for checked, false for unchecked 149 // Note: If enableEmergencyAlerts is false, it disables ALL emergency broadcasts 150 // except for cmas presidential. i.e. to receive cmas severe alerts, both 151 // enableEmergencyAlerts AND enableCmasSevereAlerts must be true. 152 boolean enableEmergencyAlerts = prefs.getBoolean( 153 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); 154 155 TelephonyManager tm = (TelephonyManager) getSystemService( 156 Context.TELEPHONY_SERVICE); 157 158 boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) || 159 "br".equals(tm.getSimCountryIso()); 160 161 boolean enableChannel50Alerts = enableChannel50Support && 162 prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_50_ALERTS, true); 163 164 // Note: ETWS is for 3GPP only 165 boolean enableEtwsTestAlerts = prefs.getBoolean( 166 CellBroadcastSettings.KEY_ENABLE_ETWS_TEST_ALERTS, false); 167 168 boolean enableCmasExtremeAlerts = prefs.getBoolean( 169 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); 170 171 boolean enableCmasSevereAlerts = prefs.getBoolean( 172 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); 173 174 boolean enableCmasAmberAlerts = prefs.getBoolean( 175 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); 176 177 boolean enableCmasTestAlerts = prefs.getBoolean( 178 CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, false); 179 180 // set up broadcast ID ranges to be used for each category 181 int cmasExtremeStart = 182 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED; 183 int cmasExtremeEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY; 184 int cmasSevereStart = 185 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED; 186 int cmasSevereEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY; 187 int cmasAmber = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY; 188 int cmasTestStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST; 189 int cmasTestEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE; 190 int cmasPresident = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL; 191 192 // set to CDMA broadcast ID rage if phone is in CDMA mode. 193 boolean isCdma = CellBroadcastReceiver.phoneIsCdma(); 194 if (isCdma) { 195 cmasExtremeStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT; 196 cmasExtremeEnd = cmasExtremeStart; 197 cmasSevereStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT; 198 cmasSevereEnd = cmasSevereStart; 199 cmasAmber = SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY; 200 cmasTestStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE; 201 cmasTestEnd = cmasTestStart; 202 cmasPresident = SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT; 203 } 204 205 SmsManager manager = SmsManager.getDefault(); 206 // Check for system property defining the emergency channel ranges to enable 207 String emergencyIdRange = isCdma ? 208 "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); 209 if (enableEmergencyAlerts) { 210 if (DBG) log("enabling emergency cell broadcast channels"); 211 if (!TextUtils.isEmpty(emergencyIdRange)) { 212 setChannelRange(manager, emergencyIdRange, true); 213 } else { 214 // No emergency channel system property, enable all emergency channels 215 // that have checkbox checked 216 if (!isCdma) { 217 manager.enableCellBroadcastRange( 218 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, 219 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING); 220 if (enableEtwsTestAlerts) { 221 manager.enableCellBroadcast( 222 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 223 } 224 manager.enableCellBroadcast( 225 SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE); 226 } 227 if (enableCmasExtremeAlerts) { 228 manager.enableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 229 } 230 if (enableCmasSevereAlerts) { 231 manager.enableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 232 } 233 if (enableCmasAmberAlerts) { 234 manager.enableCellBroadcast(cmasAmber); 235 } 236 if (enableCmasTestAlerts) { 237 manager.enableCellBroadcastRange(cmasTestStart, cmasTestEnd); 238 } 239 // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2). 240 manager.enableCellBroadcast(cmasPresident); 241 } 242 if (DBG) log("enabled emergency cell broadcast channels"); 243 } else { 244 // we may have enabled these channels previously, so try to disable them 245 if (DBG) log("disabling emergency cell broadcast channels"); 246 if (!TextUtils.isEmpty(emergencyIdRange)) { 247 setChannelRange(manager, emergencyIdRange, false); 248 } else { 249 // No emergency channel system property, disable all emergency channels 250 // except for CMAS Presidential (See 3GPP TS 22.268 Section 6.2) 251 if (!isCdma) { 252 manager.disableCellBroadcastRange( 253 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, 254 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING); 255 manager.disableCellBroadcast( 256 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 257 manager.disableCellBroadcast( 258 SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE); 259 } 260 manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 261 manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 262 manager.disableCellBroadcast(cmasAmber); 263 manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd); 264 265 // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2). 266 manager.enableCellBroadcast(cmasPresident); 267 } 268 if (DBG) log("disabled emergency cell broadcast channels"); 269 } 270 271 if (isCdma) { 272 if (DBG) log("channel 50 is not aplicable for cdma"); 273 } else if (enableChannel50Alerts) { 274 if (DBG) log("enabling cell broadcast channel 50"); 275 manager.enableCellBroadcast(50); 276 if (DBG) log("enabled cell broadcast channel 50"); 277 } else { 278 if (DBG) log("disabling cell broadcast channel 50"); 279 manager.disableCellBroadcast(50); 280 if (DBG) log("disabled cell broadcast channel 50"); 281 } 282 283 // Disable per user preference/checkbox. 284 // This takes care of the case where enableEmergencyAlerts is true, 285 // but check box is unchecked to receive such as cmas severe alerts. 286 if (!enableEtwsTestAlerts && !isCdma) { 287 if (DBG) Log.d(TAG, "disabling cell broadcast ETWS test messages"); 288 manager.disableCellBroadcast( 289 SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); 290 } 291 if (!enableCmasExtremeAlerts) { 292 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS extreme"); 293 manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd); 294 } 295 if (!enableCmasSevereAlerts) { 296 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS severe"); 297 manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd); 298 } 299 if (!enableCmasAmberAlerts) { 300 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS amber"); 301 manager.disableCellBroadcast(cmasAmber); 302 } 303 if (!enableCmasTestAlerts) { 304 if (DBG) Log.d(TAG, "disabling cell broadcast CMAS test messages"); 305 manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd); 306 } 307 } catch (Exception ex) { 308 Log.e(TAG, "exception enabling cell broadcast channels", ex); 309 } 310 } 311 } 312 313 private static void log(String msg) { 314 Log.d(TAG, msg); 315 } 316 } 317