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