/* * 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.preference.PreferenceManager; import android.telephony.CarrierConfigManager; import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import com.android.cellbroadcastreceiver.CellBroadcastOtherChannelsManager.CellBroadcastChannelRange; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.gsm.SmsCbConstants; import java.util.ArrayList; 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"; private static final String COUNTRY_TAIWAN = "tw"; private static final String COUNTRY_ISRAEL = "ir"; private static final String COUNTRY_BRAZIL = "br"; public CellBroadcastConfigService() { super(TAG); // use class name for worker thread name } @Override protected void onHandleIntent(Intent intent) { if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { try { SubscriptionManager subManager = SubscriptionManager.from(getApplicationContext()); int subId = SubscriptionManager.getDefaultSmsSubscriptionId(); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { subId = SubscriptionManager.getDefaultSubscriptionId(); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID && subManager != null) { int [] subIds = subManager.getActiveSubscriptionIdList(); if (subIds.length != 0) { subId = subIds[0]; } } } if (subManager != null) { // Retrieve all the active sub ids. We only want to enable // cell broadcast on the sub we are interested in and we'll disable // it on other subs so the users will not receive duplicate messages from // multiple carriers (e.g. for multi-sim users). int [] subIds = subManager.getActiveSubscriptionIdList(); if (subIds.length != 0) { for (int id : subIds) { SmsManager manager = SmsManager.getSmsManagerForSubscriptionId(id); if (manager != null) { if (id == subId) { // Enable cell broadcast messages on this sub. log("Enable CellBroadcast on sub " + id); setCellBroadcastOnSub(manager, id, true); } else { // Disable all cell broadcast message on this sub. // This is only for multi-sim scenario. For single SIM device // we should not reach here. log("Disable CellBroadcast on sub " + id); setCellBroadcastOnSub(manager, id, false); } } } } else { // For no sim scenario. SmsManager manager = SmsManager.getDefault(); if (manager != null) { setCellBroadcastOnSub(manager, SubscriptionManager.INVALID_SUBSCRIPTION_ID, true); } } } } catch (Exception ex) { Log.e(TAG, "exception enabling cell broadcast channels", ex); } } } /** * Enable/disable cell broadcast messages id on one subscription * This includes all ETWS and CMAS alerts. * @param manager SMS manager * @param subId Subscription id * @param enableForSub True if want to enable messages on this sub (e.g default SMS). False * will disable all messages */ private void setCellBroadcastOnSub(SmsManager manager, int subId, boolean enableForSub) { 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 = enableForSub && prefs.getBoolean( CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); boolean enableEtwsAlerts = enableEmergencyAlerts; // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless // user's preference boolean enablePresidential = enableForSub; boolean enableCmasExtremeAlerts = enableEmergencyAlerts && prefs.getBoolean( CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); boolean enableCmasSevereAlerts = enableEmergencyAlerts && prefs.getBoolean( CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); boolean enableCmasAmberAlerts = enableEmergencyAlerts && prefs.getBoolean( CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); // Check if ETWS/CMAS test message is forced disabled on the device. boolean forceDisableEtwsCmasTest = CellBroadcastSettings.isFeatureEnabled(this, CarrierConfigManager.KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false); boolean enableEtwsTestAlerts = !forceDisableEtwsCmasTest && enableEmergencyAlerts && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_ETWS_TEST_ALERTS, false); boolean enableCmasTestAlerts = !forceDisableEtwsCmasTest && enableEmergencyAlerts && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, false); TelephonyManager tm = (TelephonyManager) getSystemService( Context.TELEPHONY_SERVICE); boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) || COUNTRY_BRAZIL.equals(tm.getSimCountryIso(subId)); boolean enableChannel50Alerts = enableChannel50Support && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_50_ALERTS, true); // Current Israel requires enable certain CMAS messages ids. boolean supportIsraelPwsAlerts = (COUNTRY_ISRAEL.equals(tm.getSimCountryIso(subId)) || COUNTRY_ISRAEL.equals(tm.getNetworkCountryIso(subId))); boolean supportTaiwanPwsAlerts = (COUNTRY_TAIWAN.equals(tm.getSimCountryIso(subId)) || COUNTRY_TAIWAN.equals(tm.getNetworkCountryIso(subId))); if (DBG) { log("enableEmergencyAlerts = " + enableEmergencyAlerts); log("enableEtwsAlerts = " + enableEtwsAlerts); log("enablePresidential = " + enablePresidential); log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts); log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts); log("enableCmasAmberAlerts = " + enableCmasAmberAlerts); log("forceDisableEtwsCmasTest = " + forceDisableEtwsCmasTest); log("enableEtwsTestAlerts = " + enableEtwsTestAlerts); log("enableCmasTestAlerts = " + enableCmasTestAlerts); log("enableChannel50Alerts = " + enableChannel50Alerts); log("supportIsraelPwsAlerts = " + supportIsraelPwsAlerts); log("supportTaiwanPwsAlerts = " + supportTaiwanPwsAlerts); } /** Enable CDMA CMAS series messages. */ // Enable/Disable CDMA Presidential messages. setCellBroadcastRange(manager, enablePresidential, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA, SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT); // Enable/Disable CDMA CMAS extreme messages. setCellBroadcastRange(manager, enableCmasExtremeAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA, SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT); // Enable/Disable CDMA CMAS severe messages. setCellBroadcastRange(manager, enableCmasSevereAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA, SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT); // Enable/Disable CDMA CMAS amber alert messages. setCellBroadcastRange(manager, enableCmasAmberAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA, SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY); // Enable/Disable CDMA CMAS test messages. setCellBroadcastRange(manager, enableCmasTestAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA, SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE); /** Enable GSM ETWS series messages. */ // Enable/Disable GSM ETWS messages (4352~4354). setCellBroadcastRange(manager, enableEtwsAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING, SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING); // Enable/Disable GSM ETWS messages (4356) setCellBroadcastRange(manager, enableEtwsAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE, SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE); // Enable/Disable GSM ETWS test messages (4355). setCellBroadcastRange(manager, enableEtwsTestAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE, SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE); /** Enable GSM CMAS series messages. */ // Enable/Disable GSM CMAS presidential message (4370). setCellBroadcastRange(manager, enablePresidential, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL); // Enable/Disable GSM CMAS extreme messages (4371~4372). setCellBroadcastRange(manager, enableCmasExtremeAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY); // Enable/Disable GSM CMAS severe messages (4373~4378). setCellBroadcastRange(manager, enableCmasSevereAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY); // Enable/Disable GSM CMAS amber alert messages (4379). setCellBroadcastRange(manager, enableCmasAmberAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY); // Enable/Disable GSM CMAS test messages (4380~4382). setCellBroadcastRange(manager, enableCmasTestAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE); /** Enable GSM CMAS series messages for additional languages. */ // Enable/Disable GSM CMAS presidential messages for additional languages (4383). setCellBroadcastRange(manager, enablePresidential, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE); // Enable/Disable GSM CMAS extreme messages for additional languages (4384~4385). setCellBroadcastRange(manager, enableCmasExtremeAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE); // Enable/Disable GSM CMAS severe messages for additional languages (4386~4391). setCellBroadcastRange(manager, enableCmasSevereAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE); // Enable/Disable GSM CMAS amber alert messages for additional languages (4392). setCellBroadcastRange(manager, enableCmasAmberAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE); // Enable/Disable GSM CMAS test messages for additional languages (4393~4395). setCellBroadcastRange(manager, enableCmasTestAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE, SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE); // Enable/Disable channel 50 messages for Brazil (50). setCellBroadcastRange(manager, enableChannel50Alerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_50, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_50); // Enable/Disable additional channels based on carrier specific requirement. ArrayList ranges = CellBroadcastOtherChannelsManager. getInstance().getCellBroadcastChannelRanges(getApplicationContext(), subId); if (ranges != null) { for (CellBroadcastChannelRange range: ranges) { setCellBroadcastRange(manager, enableEmergencyAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, range.mStartId, range.mEndId); } } // Enable/Disable additional channels based on country specific requirement. if (supportIsraelPwsAlerts) { // Enable/Disable Israel PWS channels (919~928). setCellBroadcastRange(manager, enableEmergencyAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_928); } else if (supportTaiwanPwsAlerts) { // Enable/Disable Taiwan PWS Chinese channel (911). setCellBroadcastRange(manager, enableEmergencyAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_911, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_911); // Enable/Disable Taiwan PWS English channel (919). setCellBroadcastRange(manager, enableEmergencyAlerts, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919, SmsCbConstants.MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919); } } /** * Enable/disable cell broadcast with messages id range * @param manager SMS manager * @param enable True for enabling cell broadcast with id range, otherwise for disabling. * @param type GSM or CDMA * @param start Cell broadcast id range start * @param end Cell broadcast id range end */ private boolean setCellBroadcastRange( SmsManager manager, boolean enable, int type, int start, int end) { if (enable) { return manager.enableCellBroadcastRange(start, end, type); } else { return manager.disableCellBroadcastRange(start, end, type); } } private static void log(String msg) { Log.d(TAG, msg); } }