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.content.Intent; 23 import android.content.SharedPreferences; 24 import android.content.res.Resources; 25 import android.preference.PreferenceManager; 26 import android.telephony.SmsManager; 27 import android.telephony.SubscriptionManager; 28 import android.util.Log; 29 30 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange; 31 import com.android.internal.annotations.VisibleForTesting; 32 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.List; 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 public CellBroadcastConfigService() { 54 super(TAG); // use class name for worker thread name 55 } 56 57 @Override 58 protected void onHandleIntent(Intent intent) { 59 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 60 try { 61 62 SubscriptionManager subManager = SubscriptionManager.from(getApplicationContext()); 63 int subId = SubscriptionManager.getDefaultSmsSubscriptionId(); 64 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 65 subId = SubscriptionManager.getDefaultSubscriptionId(); 66 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID && 67 subManager != null) { 68 int [] subIds = subManager.getActiveSubscriptionIdList(); 69 if (subIds.length != 0) { 70 subId = subIds[0]; 71 } 72 } 73 } 74 75 if (subManager != null) { 76 // Retrieve all the active sub ids. We only want to enable 77 // cell broadcast on the sub we are interested in and we'll disable 78 // it on other subs so the users will not receive duplicate messages from 79 // multiple carriers (e.g. for multi-sim users). 80 int [] subIds = subManager.getActiveSubscriptionIdList(); 81 if (subIds.length != 0) 82 { 83 for (int id : subIds) { 84 SmsManager manager = SmsManager.getSmsManagerForSubscriptionId(id); 85 if (manager != null) { 86 if (id == subId) { 87 // Enable cell broadcast messages on this sub. 88 log("Enable CellBroadcast on sub " + id); 89 setCellBroadcastOnSub(manager, true); 90 } 91 else { 92 // Disable all cell broadcast message on this sub. 93 // This is only for multi-sim scenario. For single SIM device 94 // we should not reach here. 95 log("Disable CellBroadcast on sub " + id); 96 setCellBroadcastOnSub(manager, false); 97 } 98 } 99 } 100 } 101 else { 102 // For no sim scenario. 103 SmsManager manager = SmsManager.getDefault(); 104 if (manager != null) { 105 setCellBroadcastOnSub(manager, true); 106 } 107 } 108 } 109 } catch (Exception ex) { 110 Log.e(TAG, "exception enabling cell broadcast channels", ex); 111 } 112 } 113 } 114 115 /** 116 * Enable/disable cell broadcast messages id on one subscription 117 * This includes all ETWS and CMAS alerts. 118 * @param manager SMS manager 119 * @param enableForSub True if want to enable messages on this sub (e.g default SMS). False 120 * will disable all messages 121 */ 122 @VisibleForTesting 123 public void setCellBroadcastOnSub(SmsManager manager, boolean enableForSub) { 124 125 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 126 127 // boolean for each user preference checkbox, true for checked, false for unchecked 128 // Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts 129 // except for CMAS presidential. i.e. to receive CMAS severe alerts, both 130 // enableAlertsMasterToggle AND enableCmasSevereAlerts must be true. 131 boolean enableAlertsMasterToggle = enableForSub && prefs.getBoolean( 132 CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true); 133 134 boolean enableEtwsAlerts = enableAlertsMasterToggle; 135 136 // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless 137 // user's preference 138 boolean enablePresidential = enableForSub; 139 140 boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && prefs.getBoolean( 141 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); 142 143 boolean enableCmasSevereAlerts = enableAlertsMasterToggle && prefs.getBoolean( 144 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); 145 146 boolean enableCmasAmberAlerts = enableAlertsMasterToggle && prefs.getBoolean( 147 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); 148 149 boolean enableTestAlerts = enableAlertsMasterToggle 150 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false); 151 152 boolean enableAreaUpdateInfoAlerts = Resources.getSystem().getBoolean( 153 com.android.internal.R.bool.config_showAreaUpdateInfoSettings) 154 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS, 155 false); 156 157 // Non-CMAS channels 158 boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle 159 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES, 160 true); 161 162 boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean( 163 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); 164 165 if (VDBG) { 166 log("enableAlertsMasterToggle = " + enableAlertsMasterToggle); 167 log("enableEtwsAlerts = " + enableEtwsAlerts); 168 log("enablePresidential = " + enablePresidential); 169 log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts); 170 log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts); 171 log("enableCmasAmberAlerts = " + enableCmasAmberAlerts); 172 log("enableTestAlerts = " + enableTestAlerts); 173 log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts); 174 log("enablePublicSafetyMessagesChannelAlerts = " 175 + enablePublicSafetyMessagesChannelAlerts); 176 log("enableEmergencyAlerts = " + enableEmergencyAlerts); 177 } 178 179 /** Enable CMAS series messages. */ 180 181 // Enable/Disable Presidential messages. 182 setCellBroadcastRange(manager, enablePresidential, 183 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 184 R.array.cmas_presidential_alerts_channels_range_strings)); 185 186 // Enable/Disable CMAS extreme messages. 187 setCellBroadcastRange(manager, enableCmasExtremeAlerts, 188 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 189 R.array.cmas_alert_extreme_channels_range_strings)); 190 191 // Enable/Disable CMAS severe messages. 192 setCellBroadcastRange(manager, enableCmasSevereAlerts, 193 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 194 R.array.cmas_alerts_severe_range_strings)); 195 196 // Enable/Disable CMAS amber alert messages. 197 setCellBroadcastRange(manager, enableCmasAmberAlerts, 198 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 199 R.array.cmas_amber_alerts_channels_range_strings)); 200 201 // Enable/Disable test messages. 202 setCellBroadcastRange(manager, enableTestAlerts, 203 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 204 R.array.required_monthly_test_range_strings)); 205 setCellBroadcastRange(manager, enableTestAlerts, 206 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 207 R.array.exercise_alert_range_strings)); 208 setCellBroadcastRange(manager, enableTestAlerts, 209 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 210 R.array.operator_defined_alert_range_strings)); 211 212 // Enable/Disable GSM ETWS messages. 213 setCellBroadcastRange(manager, enableEtwsAlerts, 214 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 215 R.array.etws_alerts_range_strings)); 216 217 // Enable/Disable GSM ETWS test messages. 218 setCellBroadcastRange(manager, enableTestAlerts, 219 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 220 R.array.etws_test_alerts_range_strings)); 221 222 // Enable/Disable GSM public safety messages. 223 setCellBroadcastRange(manager, enablePublicSafetyMessagesChannelAlerts, 224 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 225 R.array.public_safety_messages_channels_range_strings)); 226 227 /** Enable non-CMAS series messages. */ 228 229 setCellBroadcastRange(manager, enableEmergencyAlerts, 230 CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this, 231 R.array.emergency_alerts_channels_range_strings)); 232 233 // Enable/Disable additional channels based on carrier specific requirement. 234 ArrayList<CellBroadcastChannelRange> ranges = CellBroadcastChannelManager 235 .getInstance().getCellBroadcastChannelRanges(this, 236 R.array.additional_cbs_channels_strings); 237 if (ranges != null) { 238 for (CellBroadcastChannelRange range: ranges) { 239 boolean enableAlerts; 240 switch (range.mAlertType) { 241 case AREA: 242 enableAlerts = enableAreaUpdateInfoAlerts; 243 break; 244 case TEST: 245 enableAlerts = enableTestAlerts; 246 break; 247 default: 248 enableAlerts = enableAlertsMasterToggle; 249 } 250 setCellBroadcastRange(manager, enableAlerts, new ArrayList<>(Arrays.asList(range))); 251 } 252 } 253 } 254 /** 255 * Enable/disable cell broadcast with messages id range 256 * @param manager SMS manager 257 * @param enable True for enabling cell broadcast with id range, otherwise for disabling. 258 * @param ranges Cell broadcast id ranges 259 */ 260 private void setCellBroadcastRange( 261 SmsManager manager, boolean enable, List<CellBroadcastChannelRange> ranges) { 262 if (ranges != null) { 263 for (CellBroadcastChannelRange range: ranges) { 264 if (enable) { 265 manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRat); 266 } else { 267 manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRat); 268 } 269 } 270 } 271 } 272 273 private static void log(String msg) { 274 Log.d(TAG, msg); 275 } 276 } 277