blob: d1d1eafce9e85c1d61261e325bca73093c4ffce7 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cellbroadcastreceiver;
import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.VDBG;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.telephony.SmsManager;
import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This service manages enabling and disabling ranges of message identifiers
* that the radio should listen for. It operates independently of the other
* services and runs at boot time and after exiting airplane mode.
*
* Note that the entire range of emergency channels is enabled. Test messages
* and lower priority broadcasts are filtered out in CellBroadcastAlertService
* if the user has not enabled them in settings.
*
* TODO: add notification to re-enable channels after a radio reset.
*/
public class CellBroadcastConfigService extends IntentService {
private static final String TAG = "CellBroadcastConfigService";
static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS";
public CellBroadcastConfigService() {
super(TAG); // use class name for worker thread name
}
@Override
protected void onHandleIntent(Intent intent) {
if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) {
try {
SubscriptionManager subManager = SubscriptionManager.from(getApplicationContext());
int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
subId = SubscriptionManager.getDefaultSubscriptionId();
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID &&
subManager != null) {
int [] subIds = subManager.getActiveSubscriptionIdList();
if (subIds.length != 0) {
subId = subIds[0];
}
}
}
if (subManager != null) {
// Retrieve all the active sub ids. We only want to enable
// cell broadcast on the sub we are interested in and we'll disable
// it on other subs so the users will not receive duplicate messages from
// multiple carriers (e.g. for multi-sim users).
int [] subIds = subManager.getActiveSubscriptionIdList();
if (subIds.length != 0)
{
for (int id : subIds) {
SmsManager manager = SmsManager.getSmsManagerForSubscriptionId(id);
if (manager != null) {
if (id == subId) {
// Enable cell broadcast messages on this sub.
log("Enable CellBroadcast on sub " + id);
setCellBroadcastOnSub(manager, true);
}
else {
// Disable all cell broadcast message on this sub.
// This is only for multi-sim scenario. For single SIM device
// we should not reach here.
log("Disable CellBroadcast on sub " + id);
setCellBroadcastOnSub(manager, false);
}
}
}
}
else {
// For no sim scenario.
SmsManager manager = SmsManager.getDefault();
if (manager != null) {
setCellBroadcastOnSub(manager, true);
}
}
}
} catch (Exception ex) {
Log.e(TAG, "exception enabling cell broadcast channels", ex);
}
}
}
/**
* Enable/disable cell broadcast messages id on one subscription
* This includes all ETWS and CMAS alerts.
* @param manager SMS manager
* @param enableForSub True if want to enable messages on this sub (e.g default SMS). False
* will disable all messages
*/
@VisibleForTesting
public void setCellBroadcastOnSub(SmsManager manager, boolean enableForSub) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// boolean for each user preference checkbox, true for checked, false for unchecked
// Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts
// except for CMAS presidential. i.e. to receive CMAS severe alerts, both
// enableAlertsMasterToggle AND enableCmasSevereAlerts must be true.
boolean enableAlertsMasterToggle = enableForSub && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true);
boolean enableEtwsAlerts = enableAlertsMasterToggle;
// CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless
// user's preference
boolean enablePresidential = enableForSub;
boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true);
boolean enableCmasSevereAlerts = enableAlertsMasterToggle && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true);
boolean enableCmasAmberAlerts = enableAlertsMasterToggle && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true);
boolean enableTestAlerts = enableAlertsMasterToggle
&& prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
boolean enableAreaUpdateInfoAlerts = Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_showAreaUpdateInfoSettings)
&& prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS,
false);
boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle
&& prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES,
true);
boolean enableStateLocalTestAlerts = enableAlertsMasterToggle
&& prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS,
false);
boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean(
CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
boolean enableGeoFencingTriggerMessage = enableForSub;
if (VDBG) {
log("enableAlertsMasterToggle = " + enableAlertsMasterToggle);
log("enableEtwsAlerts = " + enableEtwsAlerts);
log("enablePresidential = " + enablePresidential);
log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts);
log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts);
log("enableCmasAmberAlerts = " + enableCmasAmberAlerts);
log("enableTestAlerts = " + enableTestAlerts);
log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts);
log("enablePublicSafetyMessagesChannelAlerts = "
+ enablePublicSafetyMessagesChannelAlerts);
log("enableStateLocalTestAlerts = " + enableStateLocalTestAlerts);
log("enableEmergencyAlerts = " + enableEmergencyAlerts);
log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage);
}
/** Enable CMAS series messages. */
// Enable/Disable Presidential messages.
setCellBroadcastRange(manager, enablePresidential,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.cmas_presidential_alerts_channels_range_strings));
// Enable/Disable CMAS extreme messages.
setCellBroadcastRange(manager, enableCmasExtremeAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.cmas_alert_extreme_channels_range_strings));
// Enable/Disable CMAS severe messages.
setCellBroadcastRange(manager, enableCmasSevereAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.cmas_alerts_severe_range_strings));
// Enable/Disable CMAS amber alert messages.
setCellBroadcastRange(manager, enableCmasAmberAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.cmas_amber_alerts_channels_range_strings));
// Enable/Disable test messages.
setCellBroadcastRange(manager, enableTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.required_monthly_test_range_strings));
setCellBroadcastRange(manager, enableTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.exercise_alert_range_strings));
setCellBroadcastRange(manager, enableTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.operator_defined_alert_range_strings));
// Enable/Disable GSM ETWS messages.
setCellBroadcastRange(manager, enableEtwsAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.etws_alerts_range_strings));
// Enable/Disable GSM ETWS test messages.
setCellBroadcastRange(manager, enableTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.etws_test_alerts_range_strings));
// Enable/Disable GSM public safety messages.
setCellBroadcastRange(manager, enablePublicSafetyMessagesChannelAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.public_safety_messages_channels_range_strings));
// Enable/Disable GSM state/local test alerts.
setCellBroadcastRange(manager, enableStateLocalTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.state_local_test_alert_range_strings));
// Enable/Disable GSM geo-fencing trigger messages.
setCellBroadcastRange(manager, enableStateLocalTestAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.geo_fencing_trigger_messages_range_strings));
/** Enable non-CMAS series messages. */
setCellBroadcastRange(manager, enableEmergencyAlerts,
CellBroadcastChannelManager.getInstance().getCellBroadcastChannelRanges(this,
R.array.emergency_alerts_channels_range_strings));
// Enable/Disable additional channels based on carrier specific requirement.
ArrayList<CellBroadcastChannelRange> ranges = CellBroadcastChannelManager
.getInstance().getCellBroadcastChannelRanges(this,
R.array.additional_cbs_channels_strings);
if (ranges != null) {
for (CellBroadcastChannelRange range: ranges) {
boolean enableAlerts;
switch (range.mAlertType) {
case AREA:
enableAlerts = enableAreaUpdateInfoAlerts;
break;
case TEST:
enableAlerts = enableTestAlerts;
break;
default:
enableAlerts = enableAlertsMasterToggle;
}
setCellBroadcastRange(manager, enableAlerts, new ArrayList<>(Arrays.asList(range)));
}
}
}
/**
* Enable/disable cell broadcast with messages id range
* @param manager SMS manager
* @param enable True for enabling cell broadcast with id range, otherwise for disabling.
* @param ranges Cell broadcast id ranges
*/
private void setCellBroadcastRange(
SmsManager manager, boolean enable, List<CellBroadcastChannelRange> ranges) {
if (ranges != null) {
for (CellBroadcastChannelRange range: ranges) {
if (enable) {
manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRat);
} else {
manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRat);
}
}
}
}
private static void log(String msg) {
Log.d(TAG, msg);
}
}