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