1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.cellbroadcastreceiver;
18 
19 import android.app.backup.BackupManager;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.os.Bundle;
23 import android.os.PersistableBundle;
24 import android.os.UserManager;
25 import android.preference.ListPreference;
26 import android.preference.Preference;
27 import android.preference.PreferenceActivity;
28 import android.preference.PreferenceCategory;
29 import android.preference.PreferenceFragment;
30 import android.preference.PreferenceScreen;
31 import android.preference.TwoStatePreference;
32 import android.provider.Settings;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.TelephonyManager;
36 import android.util.Log;
37 
38 /**
39  * Settings activity for the cell broadcast receiver.
40  */
41 public class CellBroadcastSettings extends PreferenceActivity {
42 
43     private static final String TAG = "CellBroadcastSettings";
44 
45     private static final boolean DBG = false;
46 
47     // Preference key for whether to enable emergency notifications (default enabled).
48     public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts";
49 
50     // Enable vibration on alert (unless master volume is silent).
51     public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate";
52 
53     // Speak contents of alert after playing the alert sound.
54     public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech";
55 
56     // Preference category for emergency alert and CMAS settings.
57     public static final String KEY_CATEGORY_ALERT_SETTINGS = "category_alert_settings";
58 
59     // Preference category for ETWS related settings.
60     public static final String KEY_CATEGORY_ETWS_SETTINGS = "category_etws_settings";
61 
62     // Whether to display CMAS extreme threat notifications (default is enabled).
63     public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS =
64             "enable_cmas_extreme_threat_alerts";
65 
66     // Whether to display CMAS severe threat notifications (default is enabled).
67     public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS =
68             "enable_cmas_severe_threat_alerts";
69 
70     // Whether to display CMAS amber alert messages (default is enabled).
71     public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts";
72 
73     // Preference category for development settings (enabled by settings developer options toggle).
74     public static final String KEY_CATEGORY_DEV_SETTINGS = "category_dev_settings";
75 
76     // Whether to display ETWS test messages (default is disabled).
77     public static final String KEY_ENABLE_ETWS_TEST_ALERTS = "enable_etws_test_alerts";
78 
79     // Whether to display CMAS monthly test messages (default is disabled).
80     public static final String KEY_ENABLE_CMAS_TEST_ALERTS = "enable_cmas_test_alerts";
81 
82     // Preference category for Brazil specific settings.
83     public static final String KEY_CATEGORY_BRAZIL_SETTINGS = "category_brazil_settings";
84 
85     // Preference key for whether to enable channel 50 notifications
86     // Enabled by default for phones sold in Brazil, otherwise this setting may be hidden.
87     public static final String KEY_ENABLE_CHANNEL_50_ALERTS = "enable_channel_50_alerts";
88 
89     // Preference key for initial opt-in/opt-out dialog.
90     public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
91 
92     // Alert reminder interval ("once" = single 2 minute reminder).
93     public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
94 
95     // Brazil country code
96     private static final String COUNTRY_BRAZIL = "br";
97 
98     @Override
onCreate(Bundle savedInstanceState)99     public void onCreate(Bundle savedInstanceState) {
100         super.onCreate(savedInstanceState);
101 
102         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
103         if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
104             setContentView(R.layout.cell_broadcast_disallowed_preference_screen);
105             return;
106         }
107 
108         // Display the fragment as the main content.
109         getFragmentManager().beginTransaction().replace(android.R.id.content,
110                 new CellBroadcastSettingsFragment()).commit();
111     }
112 
113     /**
114      * New fragment-style implementation of preferences.
115      */
116     public static class CellBroadcastSettingsFragment extends PreferenceFragment {
117 
118         private TwoStatePreference mExtremeCheckBox;
119         private TwoStatePreference mSevereCheckBox;
120         private TwoStatePreference mAmberCheckBox;
121         private TwoStatePreference mEmergencyCheckBox;
122         private ListPreference mReminderInterval;
123         private TwoStatePreference mSpeechCheckBox;
124         private TwoStatePreference mEtwsTestCheckBox;
125         private TwoStatePreference mChannel50CheckBox;
126         private TwoStatePreference mCmasTestCheckBox;
127         private PreferenceCategory mAlertCategory;
128         private PreferenceCategory mETWSSettingCategory;
129         private boolean mDisableSevereWhenExtremeDisabled = true;
130 
131         @Override
onCreate(Bundle savedInstanceState)132         public void onCreate(Bundle savedInstanceState) {
133             super.onCreate(savedInstanceState);
134 
135             // Load the preferences from an XML resource
136             addPreferencesFromResource(R.xml.preferences);
137 
138             PreferenceScreen preferenceScreen = getPreferenceScreen();
139 
140             mExtremeCheckBox = (TwoStatePreference)
141                     findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
142             mSevereCheckBox = (TwoStatePreference)
143                     findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
144             mAmberCheckBox = (TwoStatePreference)
145                     findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
146             mEmergencyCheckBox = (TwoStatePreference)
147                     findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
148             mReminderInterval = (ListPreference)
149                     findPreference(KEY_ALERT_REMINDER_INTERVAL);
150             mSpeechCheckBox = (TwoStatePreference)
151                     findPreference(KEY_ENABLE_ALERT_SPEECH);
152             mEtwsTestCheckBox = (TwoStatePreference)
153                     findPreference(KEY_ENABLE_ETWS_TEST_ALERTS);
154             mChannel50CheckBox = (TwoStatePreference)
155                     findPreference(KEY_ENABLE_CHANNEL_50_ALERTS);
156             mCmasTestCheckBox = (TwoStatePreference)
157                     findPreference(KEY_ENABLE_CMAS_TEST_ALERTS);
158             mAlertCategory = (PreferenceCategory)
159                     findPreference(KEY_CATEGORY_ALERT_SETTINGS);
160             mETWSSettingCategory = (PreferenceCategory)
161                     findPreference(KEY_CATEGORY_ETWS_SETTINGS);
162 
163             mDisableSevereWhenExtremeDisabled = isFeatureEnabled(getContext(),
164                     CarrierConfigManager.KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
165 
166             // Handler for settings that require us to reconfigure enabled channels in radio
167             Preference.OnPreferenceChangeListener startConfigServiceListener =
168                     new Preference.OnPreferenceChangeListener() {
169                         @Override
170                         public boolean onPreferenceChange(Preference pref, Object newValue) {
171                             CellBroadcastReceiver.startConfigService(pref.getContext());
172 
173                             if (mDisableSevereWhenExtremeDisabled) {
174                                 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
175                                     boolean isExtremeAlertChecked = (Boolean) newValue;
176                                     if (mSevereCheckBox != null) {
177                                         mSevereCheckBox.setEnabled(isExtremeAlertChecked);
178                                         mSevereCheckBox.setChecked(false);
179                                     }
180                                 }
181                             }
182 
183                             // Notify backup manager a backup pass is needed.
184                             new BackupManager(getContext()).dataChanged();
185                             return true;
186                         }
187                     };
188 
189             // Show extra settings when developer options is enabled in settings.
190             boolean enableDevSettings = Settings.Global.getInt(getContext().getContentResolver(),
191                     Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
192 
193             Resources res = getResources();
194             boolean showEtwsSettings = res.getBoolean(R.bool.show_etws_settings);
195 
196             initReminderIntervalList();
197 
198             boolean forceDisableEtwsCmasTest = CellBroadcastSettings.isFeatureEnabled(getContext(),
199                     CarrierConfigManager.KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
200 
201             boolean emergencyAlertOnOffOptionEnabled = isFeatureEnabled(getContext(),
202                     CarrierConfigManager.KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
203 
204             if (enableDevSettings || showEtwsSettings || emergencyAlertOnOffOptionEnabled) {
205                 // enable/disable all alerts except CMAS presidential alerts.
206                 if (mEmergencyCheckBox != null) {
207                     mEmergencyCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
208                 }
209             } else {
210                 mAlertCategory.removePreference(mEmergencyCheckBox);
211             }
212 
213             // Show alert settings and ETWS categories for ETWS builds and developer mode.
214             if (enableDevSettings || showEtwsSettings) {
215 
216                 if (forceDisableEtwsCmasTest) {
217                     // Remove ETWS test preference.
218                     preferenceScreen.removePreference(mETWSSettingCategory);
219 
220                     PreferenceCategory devSettingCategory =
221                             (PreferenceCategory) findPreference(KEY_CATEGORY_DEV_SETTINGS);
222 
223                     // Remove CMAS test preference.
224                     if (devSettingCategory != null) {
225                         devSettingCategory.removePreference(mCmasTestCheckBox);
226                     }
227                 }
228             } else {
229                 mAlertCategory.removePreference(mSpeechCheckBox);
230                 // Remove ETWS test preference category.
231                 preferenceScreen.removePreference(mETWSSettingCategory);
232             }
233 
234             if (!res.getBoolean(R.bool.show_cmas_settings)) {
235                 // Remove CMAS preference items in emergency alert category.
236                 mAlertCategory.removePreference(mExtremeCheckBox);
237                 mAlertCategory.removePreference(mSevereCheckBox);
238                 mAlertCategory.removePreference(mAmberCheckBox);
239             }
240 
241             TelephonyManager tm = (TelephonyManager) getContext().getSystemService(
242                     Context.TELEPHONY_SERVICE);
243 
244             // We display channel 50 enable/disable menu if one of the followings is true
245             // 1. The setting through resource overlay is set to true.
246             // 2. At least one SIM inserted is Brazilian SIM.
247 
248             boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings);
249 
250             if (!enableChannel50Support) {
251                 SubscriptionManager sm = SubscriptionManager.from(getContext());
252                 for (int subId : sm.getActiveSubscriptionIdList()) {
253                     if (COUNTRY_BRAZIL.equals(tm.getSimCountryIso(subId))) {
254                         enableChannel50Support = true;
255                         break;
256                     }
257                 }
258             }
259 
260             if (!enableChannel50Support) {
261                 preferenceScreen.removePreference(findPreference(KEY_CATEGORY_BRAZIL_SETTINGS));
262             }
263             if (!enableDevSettings) {
264                 preferenceScreen.removePreference(findPreference(KEY_CATEGORY_DEV_SETTINGS));
265             }
266 
267             if (mChannel50CheckBox != null) {
268                 mChannel50CheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
269             }
270             if (mEtwsTestCheckBox != null) {
271                 mEtwsTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
272             }
273             if (mExtremeCheckBox != null) {
274                 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
275             }
276 
277             if (mSevereCheckBox != null) {
278                 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
279                 if (mDisableSevereWhenExtremeDisabled) {
280                     if (mExtremeCheckBox != null) {
281                         mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked());
282                     }
283                 }
284             }
285             if (mAmberCheckBox != null) {
286                 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
287             }
288             if (mCmasTestCheckBox != null) {
289                 mCmasTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
290             }
291         }
292 
initReminderIntervalList()293         private void initReminderIntervalList() {
294 
295             String[] activeValues =
296                     getResources().getStringArray(R.array.alert_reminder_interval_active_values);
297             String[] allEntries =
298                     getResources().getStringArray(R.array.alert_reminder_interval_entries);
299             String[] newEntries = new String[activeValues.length];
300 
301             // Only add active interval to the list
302             for (int i = 0; i < activeValues.length; i++) {
303                 int index = mReminderInterval.findIndexOfValue(activeValues[i]);
304                 if (index != -1) {
305                     newEntries[i] = allEntries[index];
306                     if (DBG) Log.d(TAG, "Added " + allEntries[index]);
307                 } else {
308                     Log.e(TAG, "Can't find " + activeValues[i]);
309                 }
310             }
311 
312             mReminderInterval.setEntries(newEntries);
313             mReminderInterval.setEntryValues(activeValues);
314             mReminderInterval.setSummary(mReminderInterval.getEntry());
315             mReminderInterval.setOnPreferenceChangeListener(
316                     new Preference.OnPreferenceChangeListener() {
317                         @Override
318                         public boolean onPreferenceChange(Preference pref, Object newValue) {
319                             final ListPreference listPref = (ListPreference) pref;
320                             final int idx = listPref.findIndexOfValue((String) newValue);
321                             listPref.setSummary(listPref.getEntries()[idx]);
322                             return true;
323                         }
324                     });
325         }
326     }
327 
isFeatureEnabled(Context context, String feature, boolean defaultValue)328     public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
329         int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
330         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
331             subId = SubscriptionManager.getDefaultSubscriptionId();
332             if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
333                 return defaultValue;
334             }
335         }
336 
337         CarrierConfigManager configManager =
338                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
339 
340         if (configManager != null) {
341             PersistableBundle carrierConfig = configManager.getConfigForSubId(subId);
342 
343             if (carrierConfig != null) {
344                 return carrierConfig.getBoolean(feature, defaultValue);
345             }
346         }
347 
348         return defaultValue;
349     }
350 }
351