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