150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby/*
250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Copyright (C) 2011 The Android Open Source Project
350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * you may not use this file except in compliance with the License.
650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * You may obtain a copy of the License at
750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
1050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Unless required by applicable law or agreed to in writing, software
1150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
1250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * See the License for the specific language governing permissions and
1450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * limitations under the License.
1550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby */
1650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypackage com.android.cellbroadcastreceiver;
1850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.app.IntentService;
2050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.Intent;
2150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.SharedPreferences;
2250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.res.Resources;
2359610ad5074acb5305c353a53c01676eb8258887Jake Hambyimport android.os.SystemProperties;
2450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.preference.PreferenceManager;
2550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.telephony.SmsCbConstants;
2650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.telephony.SmsManager;
2759610ad5074acb5305c353a53c01676eb8258887Jake Hambyimport android.text.TextUtils;
2850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.util.Log;
2950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport com.android.internal.telephony.gsm.SmsCbHeader;
3150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport static com.android.cellbroadcastreceiver.CellBroadcastReceiver.DBG;
3350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby/**
3550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * This service manages enabling and disabling ranges of message identifiers
3650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * that the radio should listen for. It operates independently of the other
3750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * services and runs at boot time and after exiting airplane mode.
3850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
3950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Note that the entire range of emergency channels is enabled. Test messages
4050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * and lower priority broadcasts are filtered out in CellBroadcastAlertService
4150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * if the user has not enabled them in settings.
4250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
4350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * TODO: add notification to re-enable channels after a radio reset.
4450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby */
4550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypublic class CellBroadcastConfigService extends IntentService {
4650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private static final String TAG = "CellBroadcastConfigService";
4750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS";
4950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
5050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public CellBroadcastConfigService() {
5150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        super(TAG);          // use class name for worker thread name
5250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
5350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
5459610ad5074acb5305c353a53c01676eb8258887Jake Hamby    private void setChannelRange(SmsManager manager, String ranges, boolean enable) {
5559610ad5074acb5305c353a53c01676eb8258887Jake Hamby        try {
5659610ad5074acb5305c353a53c01676eb8258887Jake Hamby            for (String channelRange : ranges.split(",")) {
5759610ad5074acb5305c353a53c01676eb8258887Jake Hamby                int dashIndex = channelRange.indexOf('-');
5859610ad5074acb5305c353a53c01676eb8258887Jake Hamby                if (dashIndex != -1) {
5959610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    int startId = Integer.decode(channelRange.substring(0, dashIndex));
6059610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    int endId = Integer.decode(channelRange.substring(dashIndex + 1));
6159610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    if (enable) {
6259610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        if (DBG) Log.d(TAG, "enabling emergency IDs " + startId + '-' + endId);
6359610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.enableCellBroadcastRange(startId, endId);
6459610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    } else {
6559610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        if (DBG) Log.d(TAG, "disabling emergency IDs " + startId + '-' + endId);
6659610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.disableCellBroadcastRange(startId, endId);
6759610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    }
6859610ad5074acb5305c353a53c01676eb8258887Jake Hamby                } else {
6959610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    int messageId = Integer.decode(channelRange);
7059610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    if (enable) {
7159610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        if (DBG) Log.d(TAG, "enabling emergency message ID " + messageId);
7259610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.enableCellBroadcast(messageId);
7359610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    } else {
7459610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        if (DBG) Log.d(TAG, "disabling emergency message ID " + messageId);
7559610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.disableCellBroadcast(messageId);
7659610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    }
7759610ad5074acb5305c353a53c01676eb8258887Jake Hamby                }
7859610ad5074acb5305c353a53c01676eb8258887Jake Hamby            }
7959610ad5074acb5305c353a53c01676eb8258887Jake Hamby        } catch (NumberFormatException e) {
8059610ad5074acb5305c353a53c01676eb8258887Jake Hamby            Log.e(TAG, "Number Format Exception parsing emergency channel range", e);
8159610ad5074acb5305c353a53c01676eb8258887Jake Hamby        }
8259610ad5074acb5305c353a53c01676eb8258887Jake Hamby    }
8359610ad5074acb5305c353a53c01676eb8258887Jake Hamby
84f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby    static boolean isOperatorDefinedEmergencyId(int messageId) {
85f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        // Check for system property defining the emergency channel ranges to enable
86f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        String emergencyIdRange = SystemProperties.get("ro.cellbroadcast.emergencyids");
87f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        if (TextUtils.isEmpty(emergencyIdRange)) {
88f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby            return false;
89f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        }
90f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        try {
91f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby            for (String channelRange : emergencyIdRange.split(",")) {
92f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                int dashIndex = channelRange.indexOf('-');
93f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                if (dashIndex != -1) {
94f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    int startId = Integer.decode(channelRange.substring(0, dashIndex));
95f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    int endId = Integer.decode(channelRange.substring(dashIndex + 1));
96f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    if (messageId >= startId && messageId <= endId) {
97f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                        return true;
98f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    }
99f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                } else {
100f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    int emergencyMessageId = Integer.decode(channelRange);
101f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    if (emergencyMessageId == messageId) {
102f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                        return true;
103f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                    }
104f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby                }
105f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby            }
106f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        } catch (NumberFormatException e) {
107f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby            Log.e(TAG, "Number Format Exception parsing emergency channel range", e);
108f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        }
109f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby        return false;
110f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby    }
111f88de2b37383f138b3c7d876bdc3b6b6fae7b728Jake Hamby
11250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    @Override
11350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    protected void onHandleIntent(Intent intent) {
11450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) {
11550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            try {
11650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
11750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Resources res = getResources();
11850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
11959610ad5074acb5305c353a53c01676eb8258887Jake Hamby                // Check for system property defining the emergency channel ranges to enable
12059610ad5074acb5305c353a53c01676eb8258887Jake Hamby                String emergencyIdRange = SystemProperties.get("ro.cellbroadcast.emergencyids");
12159610ad5074acb5305c353a53c01676eb8258887Jake Hamby
12250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                boolean enableEmergencyAlerts = prefs.getBoolean(
12350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                        CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
12450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
12550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                boolean enableChannel50Alerts = res.getBoolean(R.bool.show_brazil_settings) &&
12650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                        prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_50_ALERTS, true);
12750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
12850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                SmsManager manager = SmsManager.getDefault();
12950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                if (enableEmergencyAlerts) {
13050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "enabling emergency cell broadcast channels");
13159610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    if (!TextUtils.isEmpty(emergencyIdRange)) {
13259610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        setChannelRange(manager, emergencyIdRange, true);
13359610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    } else {
13459610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        // No emergency channel system property, enable all emergency channels
13559610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.enableCellBroadcastRange(
13659610ad5074acb5305c353a53c01676eb8258887Jake Hamby                                SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER,
13759610ad5074acb5305c353a53c01676eb8258887Jake Hamby                                SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER);
13859610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    }
13950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "enabled emergency cell broadcast channels");
14050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                } else {
14150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    // we may have enabled these channels previously, so try to disable them
14250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "disabling emergency cell broadcast channels");
14359610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    if (!TextUtils.isEmpty(emergencyIdRange)) {
14459610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        setChannelRange(manager, emergencyIdRange, false);
14559610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    } else {
14659610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        // No emergency channel system property, disable all emergency channels
14759610ad5074acb5305c353a53c01676eb8258887Jake Hamby                        manager.disableCellBroadcastRange(
14859610ad5074acb5305c353a53c01676eb8258887Jake Hamby                                SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER,
14959610ad5074acb5305c353a53c01676eb8258887Jake Hamby                                SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER);
15059610ad5074acb5305c353a53c01676eb8258887Jake Hamby                    }
15150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "disabled emergency cell broadcast channels");
15250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                }
15350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
15450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                if (enableChannel50Alerts) {
15550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "enabling cell broadcast channel 50");
15650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    manager.enableCellBroadcast(50);
15750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "enabled cell broadcast channel 50");
15850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                } else {
15950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "disabling cell broadcast channel 50");
16050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    manager.disableCellBroadcast(50);
16150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    if (DBG) Log.d(TAG, "disabled cell broadcast channel 50");
16250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                }
16350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            } catch (Exception ex) {
16450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "exception enabling cell broadcast channels", ex);
16550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
16650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
16750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
16850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby}
169