/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.cellbroadcastreceiver; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.telephony.CellBroadcastMessage; import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.gsm.SmsCbConstants; import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.DBG; /** * This service manages enabling and disabling ranges of message identifiers * that the radio should listen for. It operates independently of the other * services and runs at boot time and after exiting airplane mode. * * Note that the entire range of emergency channels is enabled. Test messages * and lower priority broadcasts are filtered out in CellBroadcastAlertService * if the user has not enabled them in settings. * * TODO: add notification to re-enable channels after a radio reset. */ public class CellBroadcastConfigService extends IntentService { private static final String TAG = "CellBroadcastConfigService"; static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS"; static final String EMERGENCY_BROADCAST_RANGE_GSM = "ro.cb.gsm.emergencyids"; public CellBroadcastConfigService() { super(TAG); // use class name for worker thread name } private static void setChannelRange(SmsManager manager, String ranges, boolean enable) { if (DBG)log("setChannelRange: " + ranges); try { for (String channelRange : ranges.split(",")) { int dashIndex = channelRange.indexOf('-'); if (dashIndex != -1) { int startId = Integer.decode(channelRange.substring(0, dashIndex).trim()); int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim()); if (enable) { if (DBG) log("enabling emergency IDs " + startId + '-' + endId); manager.enableCellBroadcastRange(startId, endId, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } else { if (DBG) log("disabling emergency IDs " + startId + '-' + endId); manager.disableCellBroadcastRange(startId, endId, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } } else { int messageId = Integer.decode(channelRange.trim()); if (enable) { if (DBG) log("enabling emergency message ID " + messageId); manager.enableCellBroadcast(messageId, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } else { if (DBG) log("disabling emergency message ID " + messageId); manager.disableCellBroadcast(messageId, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } } } } catch (NumberFormatException e) { Log.e(TAG, "Number Format Exception parsing emergency channel range", e); } // Make sure CMAS Presidential is enabled (See 3GPP TS 22.268 Section 6.2). if (DBG) log("setChannelRange: enabling CMAS Presidential"); manager.enableCellBroadcast(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); // register Taiwan PWS 4383 also, by default manager.enableCellBroadcast( SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } /** * Returns true if this is a standard or operator-defined emergency alert message. * This includes all ETWS and CMAS alerts, except for AMBER alerts. * @param message the message to test * @return true if the message is an emergency alert; false otherwise */ static boolean isEmergencyAlertMessage(CellBroadcastMessage message) { if (message.isEmergencyAlertMessage()) { return true; } // Check for system property defining the emergency channel ranges to enable String emergencyIdRange = (CellBroadcastReceiver.phoneIsCdma(message.getSubId())) ? "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); if (TextUtils.isEmpty(emergencyIdRange)) { return false; } try { int messageId = message.getServiceCategory(); for (String channelRange : emergencyIdRange.split(",")) { int dashIndex = channelRange.indexOf('-'); if (dashIndex != -1) { int startId = Integer.decode(channelRange.substring(0, dashIndex).trim()); int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim()); if (messageId >= startId && messageId <= endId) { return true; } } else { int emergencyMessageId = Integer.decode(channelRange.trim()); if (emergencyMessageId == messageId) { return true; } } } } catch (NumberFormatException e) { Log.e(TAG, "Number Format Exception parsing emergency channel range", e); } return false; } @Override protected void onHandleIntent(Intent intent) { if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { int subId = intent.getExtras().getInt(PhoneConstants.SUBSCRIPTION_KEY); try { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); Resources res = getResources(); // boolean for each user preference checkbox, true for checked, false for // unchecked // Note: If enableEmergencyAlerts is false, it disables ALL emergency broadcasts // except for cmas presidential. i.e. to receive cmas severe alerts, both // enableEmergencyAlerts AND enableCmasSevereAlerts must be true. boolean enableEmergencyAlerts = SubscriptionManager.getBooleanSubscriptionProperty( subId, SubscriptionManager.CB_EMERGENCY_ALERT, true, this); TelephonyManager tm = (TelephonyManager) getSystemService( Context.TELEPHONY_SERVICE); boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) || "br".equals(tm.getSimCountryIso()); boolean enableChannel50Alerts = enableChannel50Support && SubscriptionManager.getBooleanSubscriptionProperty(subId, SubscriptionManager.CB_CHANNEL_50_ALERT, true, this); // Note: ETWS is for 3GPP only // Check if ETWS/CMAS test message is forced disabled on the device. boolean forceDisableEtwsCmasTest = CellBroadcastSettings.isEtwsCmasTestMessageForcedDisabled(this, subId); boolean enableEtwsTestAlerts = !forceDisableEtwsCmasTest && SubscriptionManager.getBooleanSubscriptionProperty( subId, SubscriptionManager.CB_ETWS_TEST_ALERT, false, this); boolean enableCmasExtremeAlerts = SubscriptionManager .getBooleanSubscriptionProperty(subId, SubscriptionManager.CB_EXTREME_THREAT_ALERT, true, this); boolean enableCmasSevereAlerts = SubscriptionManager.getBooleanSubscriptionProperty( subId, SubscriptionManager.CB_SEVERE_THREAT_ALERT, true, this); boolean enableCmasAmberAlerts = SubscriptionManager.getBooleanSubscriptionProperty( subId, SubscriptionManager.CB_AMBER_ALERT, true, this); boolean enableCmasTestAlerts = !forceDisableEtwsCmasTest && SubscriptionManager.getBooleanSubscriptionProperty( subId, SubscriptionManager.CB_CMAS_TEST_ALERT, false, this); // set up broadcast ID ranges to be used for each category int cmasExtremeStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED; int cmasExtremeEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY; int cmasSevereStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED; int cmasSevereEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY; int cmasAmber = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY; int cmasTestStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST; int cmasTestEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE; int cmasTestLanguageStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE; int cmasTestLanguageEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE; int cmasPresident = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL; int cmasPresidentLanguage = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE; // set to CDMA broadcast ID rage if phone is in CDMA mode. boolean isCdma = CellBroadcastReceiver.phoneIsCdma(subId); SmsManager manager = SmsManager.getSmsManagerForSubscriptionId(subId); // Check for system property defining the emergency channel ranges to enable String emergencyIdRange = isCdma ? "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM); if (enableEmergencyAlerts) { if (DBG) log("enabling emergency cell broadcast channels"); if (!TextUtils.isEmpty(emergencyIdRange)) { setChannelRange(manager, emergencyIdRange, true); } else { // No emergency channel system property, enable all emergency channels // that have checkbox checked manager.enableCellBroadcastRange( SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); if (enableEtwsTestAlerts) { manager.enableCellBroadcast( SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } manager.enableCellBroadcast( SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); if (enableCmasExtremeAlerts) { manager.enableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (enableCmasSevereAlerts) { manager.enableCellBroadcastRange(cmasSevereStart, cmasSevereEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (enableCmasAmberAlerts) { manager.enableCellBroadcast(cmasAmber, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (enableCmasTestAlerts) { manager.enableCellBroadcastRange(cmasTestStart, cmasTestEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); manager.enableCellBroadcastRange( cmasTestLanguageStart, cmasTestLanguageEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } } if (DBG) log("enabled emergency cell broadcast channels"); } else { // we may have enabled these channels previously, so try to disable them if (DBG) log("disabling emergency cell broadcast channels"); if (!TextUtils.isEmpty(emergencyIdRange)) { setChannelRange(manager, emergencyIdRange, false); } else { // No emergency channel system property, disable all emergency channels // except for CMAS Presidential (See 3GPP TS 22.268 Section 6.2) manager.disableCellBroadcastRange( SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast( SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast( SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast(cmasAmber, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (DBG) log("disabled emergency cell broadcast channels"); } // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2). manager.enableCellBroadcast(cmasPresident, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.enableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); // CMAS Presidential additional language must be on per Taiwan regulation. // Technical Specifications of the Telecommunications Land Mobile 10 (PLMN10) // 5.14.2.3 Channel 4383 shows public warning messages in English and shall not // be turned off. manager.enableCellBroadcast(cmasPresidentLanguage, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); if (enableChannel50Alerts) { if (DBG) log("enabling cell broadcast channel 50"); manager.enableCellBroadcast(50, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } else { if (DBG) log("disabling cell broadcast channel 50"); manager.disableCellBroadcast(50, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } if ("il".equals(tm.getSimCountryIso()) || "il".equals(tm.getNetworkCountryIso())) { if (DBG) log("enabling channels 919-928 for Israel"); manager.enableCellBroadcastRange(919, 928, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } else { if (DBG) log("disabling channels 919-928"); manager.disableCellBroadcastRange(919, 928, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } // Disable per user preference/checkbox. // This takes care of the case where enableEmergencyAlerts is true, // but check box is unchecked to receive such as cmas severe alerts. if (!enableEtwsTestAlerts) { if (DBG) Log.d(TAG, "disabling cell broadcast ETWS test messages"); manager.disableCellBroadcast( SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } if (!enableCmasExtremeAlerts) { // Unregister Severe alerts also, if Extreme alerts are disabled if (DBG) Log.d(TAG, "disabling cell broadcast CMAS extreme and severe"); manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (!enableCmasSevereAlerts) { if (DBG) Log.d(TAG, "disabling cell broadcast CMAS severe"); manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (!enableCmasAmberAlerts) { if (DBG) Log.d(TAG, "disabling cell broadcast CMAS amber"); manager.disableCellBroadcast(cmasAmber, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast( SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); } if (!enableCmasTestAlerts) { if (DBG) Log.d(TAG, "disabling cell broadcast CMAS test messages"); manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); manager.disableCellBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA); manager.disableCellBroadcastRange( cmasTestLanguageStart, cmasTestLanguageEnd, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM); } } catch (Exception ex) { Log.e(TAG, "exception enabling cell broadcast channels", ex); } } } private static void log(String msg) { Log.d(TAG, msg); } }