• 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"); 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.ActionBar;
20 import android.app.Activity;
21 import android.app.Fragment;
22 import android.app.backup.BackupManager;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.content.res.Resources;
27 import android.os.Bundle;
28 import android.os.PersistableBundle;
29 import android.os.UserManager;
30 import android.provider.Settings;
31 import android.support.v14.preference.PreferenceFragment;
32 import android.support.v7.preference.ListPreference;
33 import android.support.v7.preference.Preference;
34 import android.support.v7.preference.PreferenceCategory;
35 import android.support.v7.preference.PreferenceScreen;
36 import android.support.v7.preference.TwoStatePreference;
37 import android.telephony.CarrierConfigManager;
38 import android.telephony.SubscriptionManager;
39 import android.util.Log;
40 import android.view.MenuItem;
41 
42 
43 /**
44  * Settings activity for the cell broadcast receiver.
45  */
46 public class CellBroadcastSettings extends Activity {
47 
48     private static final String TAG = "CellBroadcastSettings";
49 
50     private static final boolean DBG = false;
51 
52     // Preference key for a master toggle to enable/disable all alerts message (default enabled).
53     public static final String KEY_ENABLE_ALERTS_MASTER_TOGGLE = "enable_alerts_master_toggle";
54 
55     // Preference key for whether to enable public safety messages (default enabled).
56     public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES = "enable_public_safety_messages";
57 
58     // Preference key for whether to enable emergency alerts (default enabled).
59     public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts";
60 
61     // Enable vibration on alert (unless master volume is silent).
62     public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate";
63 
64     // Speak contents of alert after playing the alert sound.
65     public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech";
66 
67     // Always play at full volume when playing the alert sound.
68     public static final String KEY_USE_FULL_VOLUME = "use_full_volume";
69 
70     // Preference category for emergency alert and CMAS settings.
71     public static final String KEY_CATEGORY_EMERGENCY_ALERTS = "category_emergency_alerts";
72 
73     // Preference category for alert preferences.
74     public static final String KEY_CATEGORY_ALERT_PREFERENCES = "category_alert_preferences";
75 
76     // Whether to display CMAS extreme threat notifications (default is enabled).
77     public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS =
78             "enable_cmas_extreme_threat_alerts";
79 
80     // Whether to display CMAS severe threat notifications (default is enabled).
81     public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS =
82             "enable_cmas_severe_threat_alerts";
83 
84     // Whether to display CMAS amber alert messages (default is enabled).
85     public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts";
86 
87     // Preference category for development settings (enabled by settings developer options toggle).
88     public static final String KEY_CATEGORY_DEV_SETTINGS = "category_dev_settings";
89 
90     // Whether to display monthly test messages (default is disabled).
91     public static final String KEY_ENABLE_TEST_ALERTS = "enable_test_alerts";
92 
93     // Preference key for whether to enable area update information notifications
94     // Enabled by default for phones sold in Brazil and India, otherwise this setting may be hidden.
95     public static final String KEY_ENABLE_AREA_UPDATE_INFO_ALERTS =
96             "enable_area_update_info_alerts";
97 
98     // Preference key for initial opt-in/opt-out dialog.
99     public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
100 
101     // Alert reminder interval ("once" = single 2 minute reminder).
102     public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
103 
104     // Preference key for emergency alerts history
105     public static final String KEY_EMERGENCY_ALERT_HISTORY = "emergency_alert_history";
106 
107     // For watch layout
108     private static final String KEY_WATCH_ALERT_REMINDER = "watch_alert_reminder";
109 
110     @Override
onCreate(Bundle savedInstanceState)111     public void onCreate(Bundle savedInstanceState) {
112         super.onCreate(savedInstanceState);
113 
114         ActionBar actionBar = getActionBar();
115         if (actionBar != null) {
116             // android.R.id.home will be triggered in onOptionsItemSelected()
117             actionBar.setDisplayHomeAsUpEnabled(true);
118         }
119 
120         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
121         if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
122             setContentView(R.layout.cell_broadcast_disallowed_preference_screen);
123             return;
124         }
125 
126         // We only add new CellBroadcastSettingsFragment if no fragment is restored.
127         Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content);
128         if (fragment == null) {
129             getFragmentManager().beginTransaction().add(android.R.id.content,
130                     new CellBroadcastSettingsFragment()).commit();
131         }
132     }
133 
134     @Override
onOptionsItemSelected(MenuItem item)135     public boolean onOptionsItemSelected(MenuItem item) {
136         switch (item.getItemId()) {
137             // Respond to the action bar's Up/Home button
138             case android.R.id.home:
139                 finish();
140                 return true;
141         }
142         return super.onOptionsItemSelected(item);
143     }
144 
145     /**
146      * New fragment-style implementation of preferences.
147      */
148     public static class CellBroadcastSettingsFragment extends PreferenceFragment {
149 
150         private TwoStatePreference mExtremeCheckBox;
151         private TwoStatePreference mSevereCheckBox;
152         private TwoStatePreference mAmberCheckBox;
153         private TwoStatePreference mMasterToggle;
154         private TwoStatePreference mPublicSafetyMessagesChannelCheckBox;
155         private TwoStatePreference mEmergencyAlertsCheckBox;
156         private ListPreference mReminderInterval;
157         private TwoStatePreference mSpeechCheckBox;
158         private TwoStatePreference mFullVolumeCheckBox;
159         private TwoStatePreference mAreaUpdateInfoCheckBox;
160         private TwoStatePreference mTestCheckBox;
161         private Preference mAlertHistory;
162         private PreferenceCategory mAlertCategory;
163         private PreferenceCategory mAlertPreferencesCategory;
164         private PreferenceCategory mDevSettingCategory;
165         private boolean mDisableSevereWhenExtremeDisabled = true;
166 
167         // WATCH
168         private TwoStatePreference mAlertReminder;
169 
170         @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)171         public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
172 
173             // Load the preferences from an XML resource
174             PackageManager pm = getActivity().getPackageManager();
175             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
176                 addPreferencesFromResource(R.xml.watch_preferences);
177             } else {
178                 addPreferencesFromResource(R.xml.preferences);
179             }
180 
181             PreferenceScreen preferenceScreen = getPreferenceScreen();
182 
183             mExtremeCheckBox = (TwoStatePreference)
184                     findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
185             mSevereCheckBox = (TwoStatePreference)
186                     findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
187             mAmberCheckBox = (TwoStatePreference)
188                     findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
189             mMasterToggle = (TwoStatePreference)
190                     findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE);
191             mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference)
192                     findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES);
193             mEmergencyAlertsCheckBox = (TwoStatePreference)
194                     findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
195             mReminderInterval = (ListPreference)
196                     findPreference(KEY_ALERT_REMINDER_INTERVAL);
197             mSpeechCheckBox = (TwoStatePreference)
198                     findPreference(KEY_ENABLE_ALERT_SPEECH);
199             mFullVolumeCheckBox = (TwoStatePreference)
200                     findPreference(KEY_USE_FULL_VOLUME);
201             mAreaUpdateInfoCheckBox = (TwoStatePreference)
202                     findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS);
203             mTestCheckBox = (TwoStatePreference)
204                     findPreference(KEY_ENABLE_TEST_ALERTS);
205             mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY);
206             mDevSettingCategory = (PreferenceCategory)
207                     findPreference(KEY_CATEGORY_DEV_SETTINGS);
208 
209             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
210                 mAlertReminder = (TwoStatePreference)
211                         findPreference(KEY_WATCH_ALERT_REMINDER);
212                 if (Integer.valueOf(mReminderInterval.getValue()) == 0) {
213                     mAlertReminder.setChecked(false);
214                 } else {
215                     mAlertReminder.setChecked(true);
216                 }
217                 mAlertReminder.setOnPreferenceChangeListener((p, newVal) -> {
218                     try {
219                         mReminderInterval.setValueIndex((Boolean) newVal ? 1 : 3);
220                     } catch (IndexOutOfBoundsException e) {
221                         mReminderInterval.setValue(String.valueOf(0));
222                         Log.w(TAG, "Setting default value");
223                     }
224                     return true;
225                 });
226                 PreferenceScreen watchScreen = (PreferenceScreen)
227                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
228                 watchScreen.removePreference(mReminderInterval);
229             } else {
230                 mAlertPreferencesCategory = (PreferenceCategory)
231                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
232                 mAlertCategory = (PreferenceCategory)
233                         findPreference(KEY_CATEGORY_EMERGENCY_ALERTS);
234             }
235 
236 
237             mDisableSevereWhenExtremeDisabled = isFeatureEnabled(getContext(),
238                     CarrierConfigManager.KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
239 
240             // Handler for settings that require us to reconfigure enabled channels in radio
241             Preference.OnPreferenceChangeListener startConfigServiceListener =
242                     new Preference.OnPreferenceChangeListener() {
243                         @Override
244                         public boolean onPreferenceChange(Preference pref, Object newValue) {
245                             CellBroadcastReceiver.startConfigService(pref.getContext());
246 
247                             if (mDisableSevereWhenExtremeDisabled) {
248                                 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
249                                     boolean isExtremeAlertChecked = (Boolean) newValue;
250                                     if (mSevereCheckBox != null) {
251                                         mSevereCheckBox.setEnabled(isExtremeAlertChecked);
252                                         mSevereCheckBox.setChecked(false);
253                                     }
254                                 }
255                             }
256 
257                             if (pref.getKey().equals(KEY_ENABLE_ALERTS_MASTER_TOGGLE)) {
258                                 boolean isEnableAlerts = (Boolean) newValue;
259                                 setAlertsEnabled(isEnableAlerts);
260                             }
261 
262                             // Notify backup manager a backup pass is needed.
263                             new BackupManager(getContext()).dataChanged();
264                             return true;
265                         }
266                     };
267 
268             // Show extra settings when developer options is enabled in settings.
269             boolean enableDevSettings = Settings.Global.getInt(getContext().getContentResolver(),
270                     Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
271 
272             Resources res = getResources();
273 
274             initReminderIntervalList();
275 
276             boolean emergencyAlertOnOffOptionEnabled = isFeatureEnabled(getContext(),
277                     CarrierConfigManager.KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
278 
279             if (enableDevSettings || emergencyAlertOnOffOptionEnabled) {
280                 // enable/disable all alerts except CMAS presidential alerts.
281                 if (mMasterToggle != null) {
282                     mMasterToggle.setOnPreferenceChangeListener(startConfigServiceListener);
283                     // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we
284                     // leave them as they are.
285                     if (!mMasterToggle.isChecked()) {
286                         setAlertsEnabled(false);
287                     }
288                 }
289             } else {
290                 if (mMasterToggle != null) preferenceScreen.removePreference(mMasterToggle);
291             }
292 
293             boolean hideTestAlertMenu = CellBroadcastSettings.isFeatureEnabled(getContext(),
294                     CarrierConfigManager.KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
295 
296             // Check if we want to hide the test alert toggle.
297             if (hideTestAlertMenu || !enableDevSettings || !isTestAlertsAvailable()) {
298                 if (mTestCheckBox != null) {
299                     mAlertCategory.removePreference(mTestCheckBox);
300                 }
301             }
302 
303             if (!enableDevSettings && !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
304                 if (mDevSettingCategory != null) {
305                     preferenceScreen.removePreference(mDevSettingCategory);
306                 }
307             }
308 
309             // Remove preferences
310             if (!res.getBoolean(R.bool.show_cmas_settings)) {
311                 // Remove CMAS preference items in emergency alert category.
312                 if (mAlertCategory != null) {
313                     if (mExtremeCheckBox != null) mAlertCategory.removePreference(mExtremeCheckBox);
314                     if (mSevereCheckBox != null) mAlertCategory.removePreference(mSevereCheckBox);
315                     if (mAmberCheckBox != null) mAlertCategory.removePreference(mAmberCheckBox);
316                 }
317             }
318 
319             if (!Resources.getSystem().getBoolean(
320                     com.android.internal.R.bool.config_showAreaUpdateInfoSettings)) {
321                 if (mAlertCategory != null) {
322                     if (mAreaUpdateInfoCheckBox != null) {
323                         mAlertCategory.removePreference(mAreaUpdateInfoCheckBox);
324                     }
325                 }
326             }
327 
328             // Remove preferences based on range configurations
329             if (CellBroadcastChannelManager.getCellBroadcastChannelRanges(
330                     this.getContext(),
331                     R.array.public_safety_messages_channels_range_strings).isEmpty()) {
332                 // Remove public safety messages
333                 if (mAlertCategory != null) {
334                     if (mPublicSafetyMessagesChannelCheckBox != null) {
335                         mAlertCategory.removePreference(mPublicSafetyMessagesChannelCheckBox);
336                     }
337                 }
338             }
339 
340             if (CellBroadcastChannelManager.getCellBroadcastChannelRanges(
341                     this.getContext(), R.array.emergency_alerts_channels_range_strings).isEmpty()) {
342                 // Remove emergency alert messages
343                 if (mAlertCategory != null) {
344                     if (mEmergencyAlertsCheckBox != null) {
345                         mAlertCategory.removePreference(mEmergencyAlertsCheckBox);
346                     }
347                 }
348             }
349 
350             if (mAreaUpdateInfoCheckBox != null) {
351                 mAreaUpdateInfoCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
352             }
353             if (mExtremeCheckBox != null) {
354                 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
355             }
356             if (mPublicSafetyMessagesChannelCheckBox != null) {
357                 mPublicSafetyMessagesChannelCheckBox.setOnPreferenceChangeListener(
358                         startConfigServiceListener);
359             }
360             if (mEmergencyAlertsCheckBox != null) {
361                 mEmergencyAlertsCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
362             }
363             if (mSevereCheckBox != null) {
364                 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
365                 if (mDisableSevereWhenExtremeDisabled) {
366                     if (mExtremeCheckBox != null) {
367                         mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked());
368                     }
369                 }
370             }
371             if (mAmberCheckBox != null) {
372                 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
373             }
374             if (mTestCheckBox != null) {
375                 mTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
376             }
377 
378             if (mAlertHistory != null) {
379                 mAlertHistory.setOnPreferenceClickListener(
380                         new Preference.OnPreferenceClickListener() {
381                             @Override
382                             public boolean onPreferenceClick(final Preference preference) {
383                                 final Intent intent = new Intent(getContext(),
384                                         CellBroadcastListActivity.class);
385                                 startActivity(intent);
386                                 return true;
387                             }
388                         });
389             }
390         }
391 
isTestAlertsAvailable()392         private boolean isTestAlertsAvailable() {
393             return !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
394                     this.getContext(), R.array.required_monthly_test_range_strings).isEmpty()
395                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
396                             this.getContext(), R.array.exercise_alert_range_strings).isEmpty()
397                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
398                             this.getContext(), R.array.operator_defined_alert_range_strings)
399                     .isEmpty()
400                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
401                             this.getContext(), R.array.etws_test_alerts_range_strings).isEmpty();
402         }
403 
initReminderIntervalList()404         private void initReminderIntervalList() {
405 
406             String[] activeValues =
407                     getResources().getStringArray(R.array.alert_reminder_interval_active_values);
408             String[] allEntries =
409                     getResources().getStringArray(R.array.alert_reminder_interval_entries);
410             String[] newEntries = new String[activeValues.length];
411 
412             // Only add active interval to the list
413             for (int i = 0; i < activeValues.length; i++) {
414                 int index = mReminderInterval.findIndexOfValue(activeValues[i]);
415                 if (index != -1) {
416                     newEntries[i] = allEntries[index];
417                     if (DBG) Log.d(TAG, "Added " + allEntries[index]);
418                 } else {
419                     Log.e(TAG, "Can't find " + activeValues[i]);
420                 }
421             }
422 
423             mReminderInterval.setEntries(newEntries);
424             mReminderInterval.setEntryValues(activeValues);
425             mReminderInterval.setSummary(mReminderInterval.getEntry());
426             mReminderInterval.setOnPreferenceChangeListener(
427                     new Preference.OnPreferenceChangeListener() {
428                         @Override
429                         public boolean onPreferenceChange(Preference pref, Object newValue) {
430                             final ListPreference listPref = (ListPreference) pref;
431                             final int idx = listPref.findIndexOfValue((String) newValue);
432                             listPref.setSummary(listPref.getEntries()[idx]);
433                             return true;
434                         }
435                     });
436         }
437 
438 
setAlertsEnabled(boolean alertsEnabled)439         private void setAlertsEnabled(boolean alertsEnabled) {
440             if (mSevereCheckBox != null) {
441                 mSevereCheckBox.setEnabled(alertsEnabled);
442                 mSevereCheckBox.setChecked(alertsEnabled);
443             }
444             if (mExtremeCheckBox != null) {
445                 mExtremeCheckBox.setEnabled(alertsEnabled);
446                 mExtremeCheckBox.setChecked(alertsEnabled);
447             }
448             if (mAmberCheckBox != null) {
449                 mAmberCheckBox.setEnabled(alertsEnabled);
450                 mAmberCheckBox.setChecked(alertsEnabled);
451             }
452             if (mAreaUpdateInfoCheckBox != null) {
453                 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled);
454                 mAreaUpdateInfoCheckBox.setChecked(alertsEnabled);
455             }
456             if (mAlertPreferencesCategory != null) {
457                 mAlertPreferencesCategory.setEnabled(alertsEnabled);
458             }
459             if (mDevSettingCategory != null) {
460                 mDevSettingCategory.setEnabled(alertsEnabled);
461             }
462             if (mEmergencyAlertsCheckBox != null) {
463                 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled);
464                 mEmergencyAlertsCheckBox.setChecked(alertsEnabled);
465             }
466             if (mPublicSafetyMessagesChannelCheckBox != null) {
467                 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled);
468                 mPublicSafetyMessagesChannelCheckBox.setChecked(alertsEnabled);
469             }
470         }
471     }
472 
isFeatureEnabled(Context context, String feature, boolean defaultValue)473     public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
474         int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
475         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
476             subId = SubscriptionManager.getDefaultSubscriptionId();
477             if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
478                 return defaultValue;
479             }
480         }
481 
482         CarrierConfigManager configManager =
483                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
484 
485         if (configManager != null) {
486             PersistableBundle carrierConfig = configManager.getConfigForSubId(subId);
487 
488             if (carrierConfig != null) {
489                 return carrierConfig.getBoolean(feature, defaultValue);
490             }
491         }
492 
493         return defaultValue;
494     }
495 }
496