CellBroadcastConfigService.java revision 2ed83017c08758e9f215a3dd36242c17a7c0bc6c
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
17package com.android.cellbroadcastreceiver;
18
19import android.app.IntentService;
20import android.content.Context;
21import android.content.Intent;
22import android.content.SharedPreferences;
23import android.content.res.Resources;
24import android.os.SystemProperties;
25import android.preference.PreferenceManager;
26import android.telephony.CellBroadcastMessage;
27import android.telephony.SmsManager;
28import android.telephony.TelephonyManager;
29import android.text.TextUtils;
30import android.util.Log;
31
32import com.android.internal.telephony.cdma.sms.SmsEnvelope;
33import com.android.internal.telephony.gsm.SmsCbConstants;
34
35import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.DBG;
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 */
48public class CellBroadcastConfigService extends IntentService {
49    private static final String TAG = "CellBroadcastConfigService";
50
51    static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS";
52
53    static final String EMERGENCY_BROADCAST_RANGE_GSM =
54            "ro.cb.gsm.emergencyids";
55
56    public CellBroadcastConfigService() {
57        super(TAG);          // use class name for worker thread name
58    }
59
60    private static void setChannelRange(SmsManager manager, String ranges, boolean enable) {
61        if (DBG)log("setChannelRange: " + ranges);
62
63        try {
64            for (String channelRange : ranges.split(",")) {
65                int dashIndex = channelRange.indexOf('-');
66                if (dashIndex != -1) {
67                    int startId = Integer.decode(channelRange.substring(0, dashIndex).trim());
68                    int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim());
69                    if (enable) {
70                        if (DBG) log("enabling emergency IDs " + startId + '-' + endId);
71                        manager.enableCellBroadcastRange(startId, endId);
72                    } else {
73                        if (DBG) log("disabling emergency IDs " + startId + '-' + endId);
74                        manager.disableCellBroadcastRange(startId, endId);
75                    }
76                } else {
77                    int messageId = Integer.decode(channelRange.trim());
78                    if (enable) {
79                        if (DBG) log("enabling emergency message ID " + messageId);
80                        manager.enableCellBroadcast(messageId);
81                    } else {
82                        if (DBG) log("disabling emergency message ID " + messageId);
83                        manager.disableCellBroadcast(messageId);
84                    }
85                }
86            }
87        } catch (NumberFormatException e) {
88            Log.e(TAG, "Number Format Exception parsing emergency channel range", e);
89        }
90
91        // Make sure CMAS Presidential is enabled (See 3GPP TS 22.268 Section 6.2).
92        if (DBG) log("setChannelRange: enabling CMAS Presidential");
93        if (CellBroadcastReceiver.phoneIsCdma()) {
94            manager.enableCellBroadcast(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT);
95        } else {
96            manager.enableCellBroadcast(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL);
97            // register Taiwan PWS 4383 also, by default
98            manager.enableCellBroadcast(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE);
99        }
100    }
101
102    /**
103     * Returns true if this is a standard or operator-defined emergency alert message.
104     * This includes all ETWS and CMAS alerts, except for AMBER alerts.
105     * @param message the message to test
106     * @return true if the message is an emergency alert; false otherwise
107     */
108    static boolean isEmergencyAlertMessage(CellBroadcastMessage message) {
109        if (message.isEmergencyAlertMessage()) {
110            return true;
111        }
112
113        // Check for system property defining the emergency channel ranges to enable
114        String emergencyIdRange = (CellBroadcastReceiver.phoneIsCdma()) ?
115                "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM);
116
117        if (TextUtils.isEmpty(emergencyIdRange)) {
118            return false;
119        }
120        try {
121            int messageId = message.getServiceCategory();
122            for (String channelRange : emergencyIdRange.split(",")) {
123                int dashIndex = channelRange.indexOf('-');
124                if (dashIndex != -1) {
125                    int startId = Integer.decode(channelRange.substring(0, dashIndex).trim());
126                    int endId = Integer.decode(channelRange.substring(dashIndex + 1).trim());
127                    if (messageId >= startId && messageId <= endId) {
128                        return true;
129                    }
130                } else {
131                    int emergencyMessageId = Integer.decode(channelRange.trim());
132                    if (emergencyMessageId == messageId) {
133                        return true;
134                    }
135                }
136            }
137        } catch (NumberFormatException e) {
138            Log.e(TAG, "Number Format Exception parsing emergency channel range", e);
139        }
140        return false;
141    }
142
143    @Override
144    protected void onHandleIntent(Intent intent) {
145        if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) {
146            try {
147                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
148                Resources res = getResources();
149
150                // boolean for each user preference checkbox, true for checked, false for unchecked
151                // Note: If enableEmergencyAlerts is false, it disables ALL emergency broadcasts
152                // except for cmas presidential. i.e. to receive cmas severe alerts, both
153                // enableEmergencyAlerts AND enableCmasSevereAlerts must be true.
154                boolean enableEmergencyAlerts = prefs.getBoolean(
155                        CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
156
157                TelephonyManager tm = (TelephonyManager) getSystemService(
158                        Context.TELEPHONY_SERVICE);
159
160                boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) ||
161                        "br".equals(tm.getSimCountryIso());
162
163                boolean enableChannel50Alerts = enableChannel50Support &&
164                        prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_50_ALERTS, true);
165
166                // Note:  ETWS is for 3GPP only
167                boolean enableEtwsTestAlerts = prefs.getBoolean(
168                        CellBroadcastSettings.KEY_ENABLE_ETWS_TEST_ALERTS, false);
169
170                boolean enableCmasExtremeAlerts = prefs.getBoolean(
171                        CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true);
172
173                boolean enableCmasSevereAlerts = prefs.getBoolean(
174                        CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true);
175
176                boolean enableCmasAmberAlerts = prefs.getBoolean(
177                        CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true);
178
179                boolean enableCmasTestAlerts = prefs.getBoolean(
180                        CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, false);
181
182                // set up broadcast ID ranges to be used for each category
183                int cmasExtremeStart =
184                        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED;
185                int cmasExtremeEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY;
186                int cmasSevereStart =
187                        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED;
188                int cmasSevereEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY;
189                int cmasAmber = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY;
190                int cmasTestStart = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST;
191                int cmasTestEnd = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE;
192                int cmasPresident = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL;
193                int cmasTaiwanPWS = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE;
194
195                // set to CDMA broadcast ID rage if phone is in CDMA mode.
196                boolean isCdma = CellBroadcastReceiver.phoneIsCdma();
197                if (isCdma) {
198                    cmasExtremeStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT;
199                    cmasExtremeEnd = cmasExtremeStart;
200                    cmasSevereStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT;
201                    cmasSevereEnd = cmasSevereStart;
202                    cmasAmber = SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY;
203                    cmasTestStart = SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE;
204                    cmasTestEnd = cmasTestStart;
205                    cmasPresident = SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT;
206                }
207
208                SmsManager manager = SmsManager.getDefault();
209                // Check for system property defining the emergency channel ranges to enable
210                String emergencyIdRange = isCdma ?
211                        "" : SystemProperties.get(EMERGENCY_BROADCAST_RANGE_GSM);
212                if (enableEmergencyAlerts) {
213                    if (DBG) log("enabling emergency cell broadcast channels");
214                    if (!TextUtils.isEmpty(emergencyIdRange)) {
215                        setChannelRange(manager, emergencyIdRange, true);
216                    } else {
217                        // No emergency channel system property, enable all emergency channels
218                        // that have checkbox checked
219                        if (!isCdma) {
220                            manager.enableCellBroadcastRange(
221                                    SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING,
222                                    SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING);
223                            if (enableEtwsTestAlerts) {
224                                manager.enableCellBroadcast(
225                                        SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE);
226                            }
227                            manager.enableCellBroadcast(
228                                    SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE);
229                        }
230                        if (enableCmasExtremeAlerts) {
231                            manager.enableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd);
232                        }
233                        if (enableCmasSevereAlerts) {
234                            manager.enableCellBroadcastRange(cmasSevereStart, cmasSevereEnd);
235                        }
236                        if (enableCmasAmberAlerts) {
237                            manager.enableCellBroadcast(cmasAmber);
238                        }
239                        if (enableCmasTestAlerts) {
240                            manager.enableCellBroadcastRange(cmasTestStart, cmasTestEnd);
241                        }
242                        // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2).
243                        manager.enableCellBroadcast(cmasPresident);
244                        if (!isCdma) {
245                            // register Taiwan PWS 4383 also, by default
246                            manager.enableCellBroadcast(cmasTaiwanPWS);
247                        }
248                    }
249                    if (DBG) log("enabled emergency cell broadcast channels");
250                } else {
251                    // we may have enabled these channels previously, so try to disable them
252                    if (DBG) log("disabling emergency cell broadcast channels");
253                    if (!TextUtils.isEmpty(emergencyIdRange)) {
254                        setChannelRange(manager, emergencyIdRange, false);
255                    } else {
256                        // No emergency channel system property, disable all emergency channels
257                        // except for CMAS Presidential (See 3GPP TS 22.268 Section 6.2)
258                        if (!isCdma) {
259                            manager.disableCellBroadcastRange(
260                                    SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING,
261                                    SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING);
262                            manager.disableCellBroadcast(
263                                    SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE);
264                            manager.disableCellBroadcast(
265                                    SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE);
266                        }
267                        manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd);
268                        manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd);
269                        manager.disableCellBroadcast(cmasAmber);
270                        manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd);
271
272                        // CMAS Presidential must be on (See 3GPP TS 22.268 Section 6.2).
273                        manager.enableCellBroadcast(cmasPresident);
274                        if (!isCdma) {
275                            // register Taiwan PWS 4383 also, by default
276                            manager.enableCellBroadcast(cmasTaiwanPWS);
277                        }
278                    }
279                    if (DBG) log("disabled emergency cell broadcast channels");
280                }
281
282                if (isCdma) {
283                    if (DBG) log("channel 50 is not applicable for cdma");
284                } else if (enableChannel50Alerts) {
285                    if (DBG) log("enabling cell broadcast channel 50");
286                    manager.enableCellBroadcast(50);
287                } else {
288                    if (DBG) log("disabling cell broadcast channel 50");
289                    manager.disableCellBroadcast(50);
290                }
291
292                if ("il".equals(tm.getSimCountryIso()) || "il".equals(tm.getNetworkCountryIso())) {
293                    if (DBG) log("enabling channels 919-928 for Israel");
294                    manager.enableCellBroadcastRange(919, 928);
295                } else {
296                    if (DBG) log("disabling channels 919-928");
297                    manager.disableCellBroadcastRange(919, 928);
298                }
299
300                // Disable per user preference/checkbox.
301                // This takes care of the case where enableEmergencyAlerts is true,
302                // but check box is unchecked to receive such as cmas severe alerts.
303                if (!enableEtwsTestAlerts  && !isCdma) {
304                    if (DBG) Log.d(TAG, "disabling cell broadcast ETWS test messages");
305                    manager.disableCellBroadcast(
306                            SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE);
307                }
308                if (!enableCmasExtremeAlerts) {
309                    if (DBG) Log.d(TAG, "disabling cell broadcast CMAS extreme");
310                    manager.disableCellBroadcastRange(cmasExtremeStart, cmasExtremeEnd);
311                }
312                if (!enableCmasSevereAlerts) {
313                    if (DBG) Log.d(TAG, "disabling cell broadcast CMAS severe");
314                    manager.disableCellBroadcastRange(cmasSevereStart, cmasSevereEnd);
315                }
316                if (!enableCmasAmberAlerts) {
317                    if (DBG) Log.d(TAG, "disabling cell broadcast CMAS amber");
318                    manager.disableCellBroadcast(cmasAmber);
319                }
320                if (!enableCmasTestAlerts) {
321                    if (DBG) Log.d(TAG, "disabling cell broadcast CMAS test messages");
322                    manager.disableCellBroadcastRange(cmasTestStart, cmasTestEnd);
323                }
324            } catch (Exception ex) {
325                Log.e(TAG, "exception enabling cell broadcast channels", ex);
326            }
327        }
328    }
329
330    private static void log(String msg) {
331        Log.d(TAG, msg);
332    }
333}
334