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