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.Context; 23 import android.content.Intent; 24 import android.content.SharedPreferences; 25 import android.content.res.Resources; 26 import android.preference.PreferenceManager; 27 import android.telephony.SmsManager; 28 import android.telephony.SubscriptionInfo; 29 import android.telephony.SubscriptionManager; 30 import android.util.Log; 31 32 import androidx.annotation.NonNull; 33 34 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange; 35 import com.android.internal.annotations.VisibleForTesting; 36 37 import java.lang.reflect.Method; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.List; 41 42 /** 43 * This service manages enabling and disabling ranges of message identifiers 44 * that the radio should listen for. It operates independently of the other 45 * services and runs at boot time and after exiting airplane mode. 46 * 47 * Note that the entire range of emergency channels is enabled. Test messages 48 * and lower priority broadcasts are filtered out in CellBroadcastAlertService 49 * if the user has not enabled them in settings. 50 * 51 * TODO: add notification to re-enable channels after a radio reset. 52 */ 53 public class CellBroadcastConfigService extends IntentService { 54 private static final String TAG = "CellBroadcastConfigService"; 55 56 @VisibleForTesting 57 public static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS"; 58 CellBroadcastConfigService()59 public CellBroadcastConfigService() { 60 super(TAG); // use class name for worker thread name 61 } 62 63 @Override onHandleIntent(Intent intent)64 protected void onHandleIntent(Intent intent) { 65 if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) { 66 try { 67 SubscriptionManager subManager = (SubscriptionManager) getApplicationContext() 68 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 69 70 if (subManager != null) { 71 // Retrieve all the active subscription indice and enable cell broadcast 72 // messages on all subs. The duplication detection will be done at the 73 // frameworks. 74 int[] subIds = getActiveSubIdList(subManager); 75 if (subIds.length != 0) { 76 for (int subId : subIds) { 77 log("Enable CellBroadcast on sub " + subId); 78 enableCellBroadcastChannels(subId); 79 } 80 } else { 81 // For no sim scenario. 82 enableCellBroadcastChannels(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 83 } 84 } 85 } catch (Exception ex) { 86 Log.e(TAG, "exception enabling cell broadcast channels", ex); 87 } 88 } 89 } 90 91 @NonNull getActiveSubIdList(SubscriptionManager subMgr)92 private int[] getActiveSubIdList(SubscriptionManager subMgr) { 93 List<SubscriptionInfo> subInfos = subMgr.getActiveSubscriptionInfoList(); 94 int size = subInfos != null ? subInfos.size() : 0; 95 int[] subIds = new int[size]; 96 for (int i = 0; i < size; i++) { 97 subIds[i] = subInfos.get(i).getSubscriptionId(); 98 } 99 return subIds; 100 } 101 resetCellBroadcastChannels(int subId)102 private void resetCellBroadcastChannels(int subId) { 103 SmsManager manager; 104 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 105 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 106 } else { 107 manager = SmsManager.getDefault(); 108 } 109 110 // TODO: Call manager.resetAllCellBroadcastRanges() in Android S. 111 try { 112 Method method = SmsManager.class.getDeclaredMethod("resetAllCellBroadcastRanges"); 113 method.invoke(manager); 114 } catch (Exception e) { 115 log("Can't reset cell broadcast ranges. e=" + e); 116 } 117 } 118 119 /** 120 * Enable cell broadcast messages channels. Messages can be only received on the 121 * enabled channels. 122 * 123 * @param subId Subscription index 124 */ 125 @VisibleForTesting enableCellBroadcastChannels(int subId)126 public void enableCellBroadcastChannels(int subId) { 127 resetCellBroadcastChannels(subId); 128 129 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 130 Resources res = CellBroadcastSettings.getResources(this, subId); 131 132 // boolean for each user preference checkbox, true for checked, false for unchecked 133 // Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts 134 // except for CMAS presidential. i.e. to receive CMAS severe alerts, both 135 // enableAlertsMasterToggle AND enableCmasSevereAlerts must be true. 136 boolean enableAlertsMasterToggle = prefs.getBoolean( 137 CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true); 138 139 boolean enableEtwsAlerts = enableAlertsMasterToggle; 140 141 // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless 142 // user's preference 143 boolean enablePresidential = true; 144 145 boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && prefs.getBoolean( 146 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true); 147 148 boolean enableCmasSevereAlerts = enableAlertsMasterToggle && prefs.getBoolean( 149 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true); 150 151 boolean enableCmasAmberAlerts = enableAlertsMasterToggle && prefs.getBoolean( 152 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true); 153 154 boolean enableTestAlerts = enableAlertsMasterToggle 155 && CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext()) 156 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false); 157 158 boolean enableAreaUpdateInfoAlerts = res.getBoolean( 159 R.bool.config_showAreaUpdateInfoSettings) 160 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS, 161 false); 162 163 boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle 164 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES, 165 true); 166 boolean enableStateLocalTestAlerts = enableAlertsMasterToggle 167 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS, 168 false); 169 170 boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean( 171 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true); 172 173 boolean enableGeoFencingTriggerMessage = true; 174 175 if (VDBG) { 176 log("enableAlertsMasterToggle = " + enableAlertsMasterToggle); 177 log("enableEtwsAlerts = " + enableEtwsAlerts); 178 log("enablePresidential = " + enablePresidential); 179 log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts); 180 log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts); 181 log("enableCmasAmberAlerts = " + enableCmasAmberAlerts); 182 log("enableTestAlerts = " + enableTestAlerts); 183 log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts); 184 log("enablePublicSafetyMessagesChannelAlerts = " 185 + enablePublicSafetyMessagesChannelAlerts); 186 log("enableStateLocalTestAlerts = " + enableStateLocalTestAlerts); 187 log("enableEmergencyAlerts = " + enableEmergencyAlerts); 188 log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage); 189 } 190 191 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 192 getApplicationContext(), subId); 193 194 /** Enable CMAS series messages. */ 195 196 // Enable/Disable Presidential messages. 197 setCellBroadcastRange(subId, enablePresidential, 198 channelManager.getCellBroadcastChannelRanges( 199 R.array.cmas_presidential_alerts_channels_range_strings)); 200 201 // Enable/Disable CMAS extreme messages. 202 setCellBroadcastRange(subId, enableCmasExtremeAlerts, 203 channelManager.getCellBroadcastChannelRanges( 204 R.array.cmas_alert_extreme_channels_range_strings)); 205 206 // Enable/Disable CMAS severe messages. 207 setCellBroadcastRange(subId, enableCmasSevereAlerts, 208 channelManager.getCellBroadcastChannelRanges( 209 R.array.cmas_alerts_severe_range_strings)); 210 211 // Enable/Disable CMAS amber alert messages. 212 setCellBroadcastRange(subId, enableCmasAmberAlerts, 213 channelManager.getCellBroadcastChannelRanges( 214 R.array.cmas_amber_alerts_channels_range_strings)); 215 216 // Enable/Disable test messages. 217 setCellBroadcastRange(subId, enableTestAlerts, 218 channelManager.getCellBroadcastChannelRanges( 219 R.array.required_monthly_test_range_strings)); 220 221 // Exercise is part of test toggle with monthly test and operator defined. some carriers 222 // mandate to show test settings in UI but always enable exercise alert. 223 setCellBroadcastRange(subId, enableTestAlerts || 224 res.getBoolean(R.bool.always_enable_exercise_alert), 225 channelManager.getCellBroadcastChannelRanges( 226 R.array.exercise_alert_range_strings)); 227 228 setCellBroadcastRange(subId, enableTestAlerts, 229 channelManager.getCellBroadcastChannelRanges( 230 R.array.operator_defined_alert_range_strings)); 231 232 // Enable/Disable GSM ETWS messages. 233 setCellBroadcastRange(subId, enableEtwsAlerts, 234 channelManager.getCellBroadcastChannelRanges( 235 R.array.etws_alerts_range_strings)); 236 237 // Enable/Disable GSM ETWS test messages. 238 setCellBroadcastRange(subId, enableTestAlerts, 239 channelManager.getCellBroadcastChannelRanges( 240 R.array.etws_test_alerts_range_strings)); 241 242 // Enable/Disable GSM public safety messages. 243 setCellBroadcastRange(subId, enablePublicSafetyMessagesChannelAlerts, 244 channelManager.getCellBroadcastChannelRanges( 245 R.array.public_safety_messages_channels_range_strings)); 246 247 // Enable/Disable GSM state/local test alerts. 248 setCellBroadcastRange(subId, enableStateLocalTestAlerts, 249 channelManager.getCellBroadcastChannelRanges( 250 R.array.state_local_test_alert_range_strings)); 251 252 // Enable/Disable GSM geo-fencing trigger messages. 253 setCellBroadcastRange(subId, enableGeoFencingTriggerMessage, 254 channelManager.getCellBroadcastChannelRanges( 255 R.array.geo_fencing_trigger_messages_range_strings)); 256 257 // Enable non-CMAS series messages. 258 setCellBroadcastRange(subId, enableEmergencyAlerts, 259 channelManager.getCellBroadcastChannelRanges( 260 R.array.emergency_alerts_channels_range_strings)); 261 262 // Enable/Disable additional channels based on carrier specific requirement. 263 ArrayList<CellBroadcastChannelRange> ranges = 264 channelManager.getCellBroadcastChannelRanges( 265 R.array.additional_cbs_channels_strings); 266 267 for (CellBroadcastChannelRange range: ranges) { 268 boolean enableAlerts; 269 switch (range.mAlertType) { 270 case AREA: 271 enableAlerts = enableAreaUpdateInfoAlerts; 272 break; 273 case TEST: 274 enableAlerts = enableTestAlerts; 275 break; 276 default: 277 enableAlerts = enableAlertsMasterToggle; 278 } 279 setCellBroadcastRange(subId, enableAlerts, new ArrayList<>(Arrays.asList(range))); 280 } 281 } 282 /** 283 * Enable/disable cell broadcast with messages id range 284 * @param subId Subscription index 285 * @param enable True for enabling cell broadcast with id range, otherwise for disabling. 286 * @param ranges Cell broadcast id ranges 287 */ setCellBroadcastRange(int subId, boolean enable, List<CellBroadcastChannelRange> ranges)288 private void setCellBroadcastRange(int subId, boolean enable, 289 List<CellBroadcastChannelRange> ranges) { 290 SmsManager manager; 291 if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 292 manager = SmsManager.getSmsManagerForSubscriptionId(subId); 293 } else { 294 manager = SmsManager.getDefault(); 295 } 296 297 if (ranges != null) { 298 for (CellBroadcastChannelRange range: ranges) { 299 if (enable) { 300 manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType); 301 } else { 302 manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType); 303 } 304 } 305 } 306 } 307 log(String msg)308 private static void log(String msg) { 309 Log.d(TAG, msg); 310 } 311 } 312