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.annotation.NonNull; 20 import android.app.ActionBar; 21 import android.app.ActivityManager; 22 import android.app.Fragment; 23 import android.app.backup.BackupManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.SharedPreferences; 29 import android.content.pm.PackageManager; 30 import android.content.res.Resources; 31 import android.os.Bundle; 32 import android.os.PersistableBundle; 33 import android.os.UserManager; 34 import android.os.Vibrator; 35 import android.telephony.CarrierConfigManager; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.TelephonyManager; 38 import android.util.Log; 39 import android.view.MenuItem; 40 import android.widget.Switch; 41 42 import androidx.localbroadcastmanager.content.LocalBroadcastManager; 43 import androidx.preference.ListPreference; 44 import androidx.preference.Preference; 45 import androidx.preference.PreferenceCategory; 46 import androidx.preference.PreferenceFragment; 47 import androidx.preference.PreferenceManager; 48 import androidx.preference.TwoStatePreference; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.modules.utils.build.SdkLevel; 52 import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; 53 import com.android.settingslib.widget.MainSwitchPreference; 54 import com.android.settingslib.widget.OnMainSwitchChangeListener; 55 56 import java.util.HashMap; 57 import java.util.Map; 58 59 /** 60 * Settings activity for the cell broadcast receiver. 61 */ 62 public class CellBroadcastSettings extends CollapsingToolbarBaseActivity { 63 64 private static final String TAG = "CellBroadcastSettings"; 65 66 private static final boolean DBG = false; 67 68 /** 69 * Keys for user preferences. 70 * When adding a new preference, make sure to clear its value in resetAllPreferences. 71 */ 72 // Preference key for alert header (A text view, not clickable). 73 public static final String KEY_ALERTS_HEADER = "alerts_header"; 74 75 // Preference key for a main toggle to enable/disable all alerts message (default enabled). 76 public static final String KEY_ENABLE_ALERTS_MASTER_TOGGLE = "enable_alerts_master_toggle"; 77 78 // Preference key for whether to enable public safety messages (default enabled). 79 public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES = "enable_public_safety_messages"; 80 81 // Preference key for whether to show full-screen public safety message (pop-up dialog), If set 82 // to false, only display from message history and sms inbox if enabled. A foreground 83 // notification might also be shown if enabled. 84 public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN = 85 "enable_public_safety_messages_full_screen"; 86 87 // Preference key for whether to enable emergency alerts (default enabled). 88 public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts"; 89 90 // Enable vibration on alert (unless main volume is silent). 91 public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate"; 92 93 // Speak contents of alert after playing the alert sound. 94 public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech"; 95 96 // Play alert sound in full volume regardless Do Not Disturb is on. 97 public static final String KEY_OVERRIDE_DND = "override_dnd"; 98 99 public static final String KEY_OVERRIDE_DND_SETTINGS_CHANGED = 100 "override_dnd_settings_changed"; 101 102 // Preference category for emergency alert and CMAS settings. 103 public static final String KEY_CATEGORY_EMERGENCY_ALERTS = "category_emergency_alerts"; 104 105 // Preference category for alert preferences. 106 public static final String KEY_CATEGORY_ALERT_PREFERENCES = "category_alert_preferences"; 107 108 // Show checkbox for Presidential alerts in settings 109 // Whether to display CMAS presidential alert notifications (always enabled). 110 public static final String KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS = 111 "enable_cmas_presidential_alerts"; 112 113 // Whether to display CMAS extreme threat notifications (default is enabled). 114 public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS = 115 "enable_cmas_extreme_threat_alerts"; 116 117 // Whether to display CMAS severe threat notifications (default is enabled). 118 public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS = 119 "enable_cmas_severe_threat_alerts"; 120 121 // Whether to display CMAS amber alert messages (default is enabled). 122 public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts"; 123 124 // Whether to display monthly test messages (default is disabled). 125 public static final String KEY_ENABLE_TEST_ALERTS = "enable_test_alerts"; 126 127 // Whether to display exercise test alerts. 128 public static final String KEY_ENABLE_EXERCISE_ALERTS = "enable_exercise_alerts"; 129 130 // Whether to display operator defined test alerts 131 public static final String KEY_OPERATOR_DEFINED_ALERTS = "enable_operator_defined_alerts"; 132 133 // Whether to display state/local test messages (default disabled). 134 public static final String KEY_ENABLE_STATE_LOCAL_TEST_ALERTS = 135 "enable_state_local_test_alerts"; 136 137 // Preference key for whether to enable area update information notifications 138 // Enabled by default for phones sold in Brazil and India, otherwise this setting may be hidden. 139 public static final String KEY_ENABLE_AREA_UPDATE_INFO_ALERTS = 140 "enable_area_update_info_alerts"; 141 142 // Preference key for initial opt-in/opt-out dialog. 143 public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog"; 144 145 // Alert reminder interval ("once" = single 2 minute reminder). 146 public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval"; 147 148 // Preference key for emergency alerts history 149 public static final String KEY_EMERGENCY_ALERT_HISTORY = "emergency_alert_history"; 150 151 // Whether to receive alert in second language code 152 public static final String KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE = 153 "receive_cmas_in_second_language"; 154 155 /* End of user preferences keys section. */ 156 157 // Resource cache 158 private static final Map<Integer, Resources> sResourcesCache = new HashMap<>(); 159 160 // Intent sent from cellbroadcastreceiver to notify cellbroadcastservice that area info update 161 // is disabled/enabled. 162 private static final String AREA_INFO_UPDATE_ACTION = 163 "com.android.cellbroadcastreceiver.action.AREA_UPDATE_INFO_ENABLED"; 164 private static final String AREA_INFO_UPDATE_ENABLED_EXTRA = "enable"; 165 166 /** 167 * This permission is only granted to the cellbroadcast mainline module and thus can be 168 * used for permission check within CBR and CBS. 169 */ 170 private static final String CBR_MODULE_PERMISSION = 171 "com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY"; 172 173 // Key for shared preference which represents whether user has changed any preference 174 private static final String ANY_PREFERENCE_CHANGED_BY_USER = "any_preference_changed_by_user"; 175 176 @Override onCreate(Bundle savedInstanceState)177 public void onCreate(Bundle savedInstanceState) { 178 // for backward compatibility on R devices 179 if (!SdkLevel.isAtLeastS()) { 180 setCustomizeContentView(R.layout.cell_broadcast_list_collapsing_no_toobar); 181 } 182 super.onCreate(savedInstanceState); 183 184 // for backward compatibility on R devices 185 if (!SdkLevel.isAtLeastS()) { 186 ActionBar actionBar = getActionBar(); 187 if (actionBar != null) { 188 // android.R.id.home will be triggered in onOptionsItemSelected() 189 actionBar.setDisplayHomeAsUpEnabled(true); 190 } 191 } 192 193 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); 194 if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) { 195 setContentView(R.layout.cell_broadcast_disallowed_preference_screen); 196 return; 197 } 198 199 // We only add new CellBroadcastSettingsFragment if no fragment is restored. 200 Fragment fragment = getFragmentManager().findFragmentById( 201 com.android.settingslib.collapsingtoolbar.R.id.content_frame); 202 if (fragment == null) { 203 fragment = new CellBroadcastSettingsFragment(); 204 getFragmentManager() 205 .beginTransaction() 206 .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame, fragment) 207 .commit(); 208 } 209 } 210 211 @Override onStart()212 public void onStart() { 213 super.onStart(); 214 getWindow().addSystemFlags( 215 android.view.WindowManager.LayoutParams 216 .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 217 } 218 219 @Override onOptionsItemSelected(MenuItem item)220 public boolean onOptionsItemSelected(MenuItem item) { 221 switch (item.getItemId()) { 222 // Respond to the action bar's Up/Home button 223 case android.R.id.home: 224 finish(); 225 return true; 226 } 227 return super.onOptionsItemSelected(item); 228 } 229 230 /** 231 * Reset all user values for preferences (stored in shared preferences). 232 * 233 * @param c the application context 234 */ resetAllPreferences(Context c)235 public static void resetAllPreferences(Context c) { 236 SharedPreferences.Editor e = PreferenceManager.getDefaultSharedPreferences(c).edit(); 237 e.remove(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS) 238 .remove(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS) 239 .remove(KEY_ENABLE_CMAS_AMBER_ALERTS) 240 .remove(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES) 241 .remove(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN) 242 .remove(KEY_ENABLE_EMERGENCY_ALERTS) 243 .remove(KEY_ALERT_REMINDER_INTERVAL) 244 .remove(KEY_ENABLE_ALERT_SPEECH) 245 .remove(KEY_OVERRIDE_DND) 246 .remove(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS) 247 .remove(KEY_ENABLE_TEST_ALERTS) 248 .remove(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS) 249 .remove(KEY_ENABLE_ALERT_VIBRATE) 250 .remove(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS) 251 .remove(KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE) 252 .remove(KEY_ENABLE_EXERCISE_ALERTS) 253 .remove(KEY_OPERATOR_DEFINED_ALERTS); 254 // If the device is in test harness mode, reset main toggle should only happen on the 255 // first boot. 256 if (!ActivityManager.isRunningInUserTestHarness()) { 257 Log.d(TAG, "In not test harness mode. reset main toggle."); 258 e.remove(KEY_ENABLE_ALERTS_MASTER_TOGGLE); 259 } 260 e.commit(); 261 262 PackageManager pm = c.getPackageManager(); 263 if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 264 PreferenceManager.setDefaultValues(c, R.xml.watch_preferences, true); 265 } else { 266 PreferenceManager.setDefaultValues(c, R.xml.preferences, true); 267 } 268 setPreferenceChanged(c, false); 269 } 270 271 /** 272 * Return true if user has modified any preference manually. 273 * @param c the application context 274 * @return 275 */ hasAnyPreferenceChanged(Context c)276 public static boolean hasAnyPreferenceChanged(Context c) { 277 return PreferenceManager.getDefaultSharedPreferences(c) 278 .getBoolean(ANY_PREFERENCE_CHANGED_BY_USER, false); 279 } 280 setPreferenceChanged(Context c, boolean changed)281 private static void setPreferenceChanged(Context c, boolean changed) { 282 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(c); 283 sp.edit().putBoolean(ANY_PREFERENCE_CHANGED_BY_USER, changed).apply(); 284 } 285 286 /** 287 * New fragment-style implementation of preferences. 288 */ 289 public static class CellBroadcastSettingsFragment extends PreferenceFragment { 290 291 private TwoStatePreference mExtremeCheckBox; 292 private TwoStatePreference mSevereCheckBox; 293 private TwoStatePreference mAmberCheckBox; 294 private MainSwitchPreference mMasterToggle; 295 private TwoStatePreference mPublicSafetyMessagesChannelCheckBox; 296 private TwoStatePreference mPublicSafetyMessagesChannelFullScreenCheckBox; 297 private TwoStatePreference mEmergencyAlertsCheckBox; 298 private ListPreference mReminderInterval; 299 private TwoStatePreference mSpeechCheckBox; 300 private TwoStatePreference mOverrideDndCheckBox; 301 private TwoStatePreference mAreaUpdateInfoCheckBox; 302 private TwoStatePreference mTestCheckBox; 303 private TwoStatePreference mExerciseTestCheckBox; 304 private TwoStatePreference mOperatorDefinedCheckBox; 305 private TwoStatePreference mStateLocalTestCheckBox; 306 private TwoStatePreference mEnableVibrateCheckBox; 307 private Preference mAlertHistory; 308 private Preference mAlertsHeader; 309 private PreferenceCategory mAlertCategory; 310 private PreferenceCategory mAlertPreferencesCategory; 311 private boolean mDisableSevereWhenExtremeDisabled = true; 312 313 // Show checkbox for Presidential alerts in settings 314 private TwoStatePreference mPresidentialCheckBox; 315 316 // on/off switch in settings for receiving alert in second language code 317 private TwoStatePreference mReceiveCmasInSecondLanguageCheckBox; 318 319 private final BroadcastReceiver mTestingModeChangedReceiver = new BroadcastReceiver() { 320 @Override 321 public void onReceive(Context context, Intent intent) { 322 switch (intent.getAction()) { 323 case CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED: 324 updatePreferenceVisibility(); 325 break; 326 } 327 } 328 }; 329 initPreferences()330 private void initPreferences() { 331 mExtremeCheckBox = (TwoStatePreference) 332 findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS); 333 mSevereCheckBox = (TwoStatePreference) 334 findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS); 335 mAmberCheckBox = (TwoStatePreference) 336 findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS); 337 mMasterToggle = (MainSwitchPreference) 338 findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE); 339 mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference) 340 findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES); 341 mPublicSafetyMessagesChannelFullScreenCheckBox = (TwoStatePreference) 342 findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN); 343 mEmergencyAlertsCheckBox = (TwoStatePreference) 344 findPreference(KEY_ENABLE_EMERGENCY_ALERTS); 345 mReminderInterval = (ListPreference) 346 findPreference(KEY_ALERT_REMINDER_INTERVAL); 347 mSpeechCheckBox = (TwoStatePreference) 348 findPreference(KEY_ENABLE_ALERT_SPEECH); 349 mOverrideDndCheckBox = (TwoStatePreference) 350 findPreference(KEY_OVERRIDE_DND); 351 mAreaUpdateInfoCheckBox = (TwoStatePreference) 352 findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS); 353 mTestCheckBox = (TwoStatePreference) 354 findPreference(KEY_ENABLE_TEST_ALERTS); 355 mExerciseTestCheckBox = (TwoStatePreference) findPreference(KEY_ENABLE_EXERCISE_ALERTS); 356 mOperatorDefinedCheckBox = (TwoStatePreference) 357 findPreference(KEY_OPERATOR_DEFINED_ALERTS); 358 mStateLocalTestCheckBox = (TwoStatePreference) 359 findPreference(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS); 360 mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY); 361 mAlertsHeader = findPreference(KEY_ALERTS_HEADER); 362 mReceiveCmasInSecondLanguageCheckBox = (TwoStatePreference) findPreference 363 (KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE); 364 mEnableVibrateCheckBox = findPreference(KEY_ENABLE_ALERT_VIBRATE); 365 366 // Show checkbox for Presidential alerts in settings 367 mPresidentialCheckBox = (TwoStatePreference) 368 findPreference(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS); 369 370 PackageManager pm = getActivity().getPackageManager(); 371 if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 372 mAlertPreferencesCategory = (PreferenceCategory) 373 findPreference(KEY_CATEGORY_ALERT_PREFERENCES); 374 mAlertCategory = (PreferenceCategory) 375 findPreference(KEY_CATEGORY_EMERGENCY_ALERTS); 376 } 377 } 378 379 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)380 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 381 382 LocalBroadcastManager.getInstance(getContext()) 383 .registerReceiver(mTestingModeChangedReceiver, new IntentFilter( 384 CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED)); 385 386 // Load the preferences from an XML resource 387 PackageManager pm = getActivity().getPackageManager(); 388 if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 389 addPreferencesFromResource(R.xml.watch_preferences); 390 } else { 391 addPreferencesFromResource(R.xml.preferences); 392 } 393 394 initPreferences(); 395 396 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 397 398 mDisableSevereWhenExtremeDisabled = res.getBoolean( 399 R.bool.disable_severe_when_extreme_disabled); 400 401 final OnMainSwitchChangeListener mainSwitchListener = new OnMainSwitchChangeListener() { 402 @Override 403 public void onSwitchChanged(Switch switchView, boolean isChecked) { 404 setAlertsEnabled(isChecked); 405 } 406 }; 407 408 // Handler for settings that require us to reconfigure enabled channels in radio 409 Preference.OnPreferenceChangeListener startConfigServiceListener = 410 new Preference.OnPreferenceChangeListener() { 411 @Override 412 public boolean onPreferenceChange(Preference pref, Object newValue) { 413 CellBroadcastReceiver.startConfigService(pref.getContext(), 414 CellBroadcastConfigService.ACTION_ENABLE_CHANNELS); 415 setPreferenceChanged(getContext(), true); 416 417 if (mDisableSevereWhenExtremeDisabled) { 418 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) { 419 boolean isExtremeAlertChecked = (Boolean) newValue; 420 if (mSevereCheckBox != null) { 421 mSevereCheckBox.setEnabled(isExtremeAlertChecked); 422 mSevereCheckBox.setChecked(false); 423 } 424 } 425 } 426 427 // check if area update was disabled 428 if (pref.getKey().equals(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS)) { 429 boolean isEnabledAlert = (Boolean) newValue; 430 notifyAreaInfoUpdate(isEnabledAlert); 431 } 432 433 // Notify backup manager a backup pass is needed. 434 new BackupManager(getContext()).dataChanged(); 435 return true; 436 } 437 }; 438 439 initReminderIntervalList(); 440 441 if (mMasterToggle != null) { 442 mMasterToggle.addOnSwitchChangeListener(mainSwitchListener); 443 // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we 444 // leave them as they are. 445 if (!mMasterToggle.isChecked()) { 446 setAlertsEnabled(false); 447 } 448 } 449 // note that mPresidentialCheckBox does not use the startConfigServiceListener because 450 // the user is never allowed to change the preference 451 if (mAreaUpdateInfoCheckBox != null) { 452 mAreaUpdateInfoCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 453 } 454 if (mExtremeCheckBox != null) { 455 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 456 } 457 if (mPublicSafetyMessagesChannelCheckBox != null) { 458 mPublicSafetyMessagesChannelCheckBox.setOnPreferenceChangeListener( 459 startConfigServiceListener); 460 } 461 if (mPublicSafetyMessagesChannelFullScreenCheckBox != null) { 462 mPublicSafetyMessagesChannelFullScreenCheckBox.setOnPreferenceChangeListener( 463 startConfigServiceListener); 464 } 465 if (mEmergencyAlertsCheckBox != null) { 466 mEmergencyAlertsCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 467 } 468 if (mSevereCheckBox != null) { 469 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 470 if (mDisableSevereWhenExtremeDisabled) { 471 if (mExtremeCheckBox != null) { 472 mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked()); 473 } 474 } 475 } 476 if (mAmberCheckBox != null) { 477 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 478 } 479 if (mTestCheckBox != null) { 480 mTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 481 } 482 if (mExerciseTestCheckBox != null) { 483 mExerciseTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 484 } 485 if (mOperatorDefinedCheckBox != null) { 486 mOperatorDefinedCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 487 } 488 if (mStateLocalTestCheckBox != null) { 489 mStateLocalTestCheckBox.setOnPreferenceChangeListener( 490 startConfigServiceListener); 491 } 492 493 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 494 495 if (mOverrideDndCheckBox != null) { 496 if (!sp.getBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, false)) { 497 // If the user hasn't changed this settings yet, use the default settings 498 // from resource overlay. 499 mOverrideDndCheckBox.setChecked(res.getBoolean(R.bool.override_dnd_default)); 500 } 501 mOverrideDndCheckBox.setOnPreferenceChangeListener( 502 (pref, newValue) -> { 503 sp.edit().putBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, 504 true).apply(); 505 updateVibrationPreference((boolean) newValue); 506 return true; 507 }); 508 } 509 510 if (mAlertHistory != null) { 511 mAlertHistory.setOnPreferenceClickListener( 512 preference -> { 513 final Intent intent = new Intent(getContext(), 514 CellBroadcastListActivity.class); 515 startActivity(intent); 516 return true; 517 }); 518 } 519 520 updateVibrationPreference(sp.getBoolean(CellBroadcastSettings.KEY_OVERRIDE_DND, 521 false)); 522 updatePreferenceVisibility(); 523 } 524 525 /** 526 * Update the vibration preference based on override DND. If DND is overridden, then do 527 * not allow users to turn off vibration. 528 * 529 * @param overrideDnd {@code true} if the alert will be played at full volume, regardless 530 * DND settings. 531 */ updateVibrationPreference(boolean overrideDnd)532 private void updateVibrationPreference(boolean overrideDnd) { 533 if (mEnableVibrateCheckBox != null) { 534 if (overrideDnd) { 535 // If DND is enabled, always enable vibration. 536 mEnableVibrateCheckBox.setChecked(true); 537 } 538 // Grey out the preference if DND is overridden. 539 mEnableVibrateCheckBox.setEnabled(!overrideDnd); 540 } 541 } 542 543 /** 544 * Dynamically update each preference's visibility based on configuration. 545 */ updatePreferenceVisibility()546 private void updatePreferenceVisibility() { 547 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 548 549 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 550 getContext(), SubscriptionManager.getDefaultSubscriptionId()); 551 552 if (mMasterToggle != null) { 553 mMasterToggle.setVisible(res.getBoolean(R.bool.show_main_switch_settings)); 554 } 555 556 if (mPresidentialCheckBox != null) { 557 mPresidentialCheckBox.setVisible( 558 res.getBoolean(R.bool.show_presidential_alerts_settings)); 559 } 560 561 if (mExtremeCheckBox != null) { 562 mExtremeCheckBox.setVisible(res.getBoolean(R.bool.show_extreme_alert_settings) 563 && !channelManager.getCellBroadcastChannelRanges( 564 R.array.cmas_alert_extreme_channels_range_strings).isEmpty()); 565 } 566 567 if (mSevereCheckBox != null) { 568 mSevereCheckBox.setVisible(res.getBoolean(R.bool.show_severe_alert_settings) 569 && !channelManager.getCellBroadcastChannelRanges( 570 R.array.cmas_alerts_severe_range_strings).isEmpty()); 571 } 572 573 if (mAmberCheckBox != null) { 574 mAmberCheckBox.setVisible(res.getBoolean(R.bool.show_amber_alert_settings) 575 && !channelManager.getCellBroadcastChannelRanges( 576 R.array.cmas_amber_alerts_channels_range_strings).isEmpty()); 577 } 578 579 if (mPublicSafetyMessagesChannelCheckBox != null) { 580 mPublicSafetyMessagesChannelCheckBox.setVisible( 581 res.getBoolean(R.bool.show_public_safety_settings) 582 && !channelManager.getCellBroadcastChannelRanges( 583 R.array.public_safety_messages_channels_range_strings) 584 .isEmpty()); 585 } 586 // this is the matching full screen settings for public safety toggle. shown only if 587 // public safety toggle is displayed. 588 if (mPublicSafetyMessagesChannelFullScreenCheckBox != null) { 589 mPublicSafetyMessagesChannelFullScreenCheckBox.setVisible( 590 res.getBoolean(R.bool.show_public_safety_full_screen_settings) 591 && (mPublicSafetyMessagesChannelCheckBox != null 592 && mPublicSafetyMessagesChannelCheckBox.isVisible())); 593 } 594 595 if (mTestCheckBox != null) { 596 mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext())); 597 } 598 599 if (mExerciseTestCheckBox != null) { 600 boolean visible = false; 601 if (res.getBoolean(R.bool.show_separate_exercise_settings)) { 602 if (res.getBoolean(R.bool.show_exercise_settings) 603 || CellBroadcastReceiver.isTestingMode(getContext())) { 604 if (!channelManager.getCellBroadcastChannelRanges( 605 R.array.exercise_alert_range_strings).isEmpty()) { 606 visible = true; 607 } 608 } 609 } 610 mExerciseTestCheckBox.setVisible(visible); 611 } 612 613 if (mOperatorDefinedCheckBox != null) { 614 boolean visible = false; 615 if (res.getBoolean(R.bool.show_separate_operator_defined_settings)) { 616 if (res.getBoolean(R.bool.show_operator_defined_settings) 617 || CellBroadcastReceiver.isTestingMode(getContext())) { 618 if (!channelManager.getCellBroadcastChannelRanges( 619 R.array.operator_defined_alert_range_strings).isEmpty()) { 620 visible = true; 621 } 622 } 623 } 624 mOperatorDefinedCheckBox.setVisible(visible); 625 } 626 627 if (mEmergencyAlertsCheckBox != null) { 628 mEmergencyAlertsCheckBox.setVisible(!channelManager.getCellBroadcastChannelRanges( 629 R.array.emergency_alerts_channels_range_strings).isEmpty()); 630 } 631 632 if (mStateLocalTestCheckBox != null) { 633 mStateLocalTestCheckBox.setVisible( 634 res.getBoolean(R.bool.show_state_local_test_settings) 635 && !channelManager.getCellBroadcastChannelRanges( 636 R.array.state_local_test_alert_range_strings).isEmpty()); 637 } 638 639 if (mReceiveCmasInSecondLanguageCheckBox != null) { 640 mReceiveCmasInSecondLanguageCheckBox.setVisible(!res.getString( 641 R.string.emergency_alert_second_language_code).isEmpty()); 642 } 643 644 if (mAreaUpdateInfoCheckBox != null) { 645 mAreaUpdateInfoCheckBox.setVisible( 646 res.getBoolean(R.bool.config_showAreaUpdateInfoSettings)); 647 } 648 649 if (mOverrideDndCheckBox != null) { 650 mOverrideDndCheckBox.setVisible(res.getBoolean(R.bool.show_override_dnd_settings)); 651 } 652 653 if (mEnableVibrateCheckBox != null) { 654 // Only show vibrate toggle when override DND toggle is available to users, or when 655 // override DND default is turned off. 656 // In some countries, override DND is always on, which means vibration is always on. 657 // In that case, no need to show vibration toggle for users. 658 Vibrator vibrator = getContext().getSystemService(Vibrator.class); 659 boolean supportVibration = (vibrator != null) && vibrator.hasVibrator(); 660 mEnableVibrateCheckBox.setVisible(supportVibration 661 && (res.getBoolean(R.bool.show_override_dnd_settings) || 662 !res.getBoolean(R.bool.override_dnd))); 663 } 664 if (mAlertsHeader != null) { 665 mAlertsHeader.setVisible( 666 !getContext().getString(R.string.alerts_header_summary).isEmpty()); 667 } 668 669 if (mSpeechCheckBox != null) { 670 mSpeechCheckBox.setVisible(res.getBoolean(R.bool.show_alert_speech_setting) 671 || getActivity().getPackageManager() 672 .hasSystemFeature(PackageManager.FEATURE_WATCH)); 673 } 674 } 675 initReminderIntervalList()676 private void initReminderIntervalList() { 677 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 678 679 String[] activeValues = 680 res.getStringArray(R.array.alert_reminder_interval_active_values); 681 String[] allEntries = res.getStringArray(R.array.alert_reminder_interval_entries); 682 String[] newEntries = new String[activeValues.length]; 683 684 // Only add active interval to the list 685 for (int i = 0; i < activeValues.length; i++) { 686 int index = mReminderInterval.findIndexOfValue(activeValues[i]); 687 if (index != -1) { 688 newEntries[i] = allEntries[index]; 689 if (DBG) Log.d(TAG, "Added " + allEntries[index]); 690 } else { 691 Log.e(TAG, "Can't find " + activeValues[i]); 692 } 693 } 694 695 mReminderInterval.setEntries(newEntries); 696 mReminderInterval.setEntryValues(activeValues); 697 mReminderInterval.setSummary(mReminderInterval.getEntry()); 698 mReminderInterval.setOnPreferenceChangeListener( 699 new Preference.OnPreferenceChangeListener() { 700 @Override 701 public boolean onPreferenceChange(Preference pref, Object newValue) { 702 final ListPreference listPref = (ListPreference) pref; 703 final int idx = listPref.findIndexOfValue((String) newValue); 704 listPref.setSummary(listPref.getEntries()[idx]); 705 return true; 706 } 707 }); 708 } 709 710 setAlertsEnabled(boolean alertsEnabled)711 private void setAlertsEnabled(boolean alertsEnabled) { 712 if (mSevereCheckBox != null) { 713 mSevereCheckBox.setEnabled(alertsEnabled); 714 mSevereCheckBox.setChecked(alertsEnabled); 715 } 716 if (mExtremeCheckBox != null) { 717 mExtremeCheckBox.setEnabled(alertsEnabled); 718 mExtremeCheckBox.setChecked(alertsEnabled); 719 } 720 if (mAmberCheckBox != null) { 721 mAmberCheckBox.setEnabled(alertsEnabled); 722 mAmberCheckBox.setChecked(alertsEnabled); 723 } 724 if (mAreaUpdateInfoCheckBox != null) { 725 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled); 726 mAreaUpdateInfoCheckBox.setChecked(alertsEnabled); 727 notifyAreaInfoUpdate(alertsEnabled); 728 } 729 if (mEmergencyAlertsCheckBox != null) { 730 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled); 731 mEmergencyAlertsCheckBox.setChecked(alertsEnabled); 732 } 733 if (mPublicSafetyMessagesChannelCheckBox != null) { 734 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled); 735 mPublicSafetyMessagesChannelCheckBox.setChecked(alertsEnabled); 736 } 737 if (mStateLocalTestCheckBox != null) { 738 mStateLocalTestCheckBox.setEnabled(alertsEnabled); 739 mStateLocalTestCheckBox.setChecked(alertsEnabled); 740 } 741 if (mTestCheckBox != null) { 742 mTestCheckBox.setEnabled(alertsEnabled); 743 mTestCheckBox.setChecked(alertsEnabled); 744 } 745 if (mExerciseTestCheckBox != null) { 746 mExerciseTestCheckBox.setEnabled(alertsEnabled); 747 mExerciseTestCheckBox.setChecked(alertsEnabled); 748 } 749 if (mOperatorDefinedCheckBox != null) { 750 mOperatorDefinedCheckBox.setEnabled(alertsEnabled); 751 mOperatorDefinedCheckBox.setChecked(alertsEnabled); 752 } 753 } 754 notifyAreaInfoUpdate(boolean enabled)755 private void notifyAreaInfoUpdate(boolean enabled) { 756 Intent areaInfoIntent = new Intent(AREA_INFO_UPDATE_ACTION); 757 areaInfoIntent.putExtra(AREA_INFO_UPDATE_ENABLED_EXTRA, enabled); 758 // sending broadcast protected by the permission which is only 759 // granted for CBR mainline module. 760 getContext().sendBroadcast(areaInfoIntent, CBR_MODULE_PERMISSION); 761 } 762 763 764 @Override onResume()765 public void onResume() { 766 super.onResume(); 767 updatePreferenceVisibility(); 768 } 769 770 @Override onDestroy()771 public void onDestroy() { 772 super.onDestroy(); 773 LocalBroadcastManager.getInstance(getContext()) 774 .unregisterReceiver(mTestingModeChangedReceiver); 775 } 776 } 777 isTestAlertsToggleVisible(Context context)778 public static boolean isTestAlertsToggleVisible(Context context) { 779 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context, 780 SubscriptionManager.getDefaultSubscriptionId()); 781 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(context); 782 boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges( 783 R.array.required_monthly_test_range_strings).isEmpty() 784 || (!channelManager.getCellBroadcastChannelRanges( 785 R.array.exercise_alert_range_strings).isEmpty() 786 /** exercise toggle is controlled under the main test toggle */ 787 && (!res.getBoolean(R.bool.show_separate_exercise_settings))) 788 || (!channelManager.getCellBroadcastChannelRanges( 789 R.array.operator_defined_alert_range_strings).isEmpty() 790 /** operator defined toggle is controlled under the main test toggle */ 791 && (!res.getBoolean(R.bool.show_separate_operator_defined_settings))) 792 || !channelManager.getCellBroadcastChannelRanges( 793 R.array.etws_test_alerts_range_strings).isEmpty(); 794 795 return (res.getBoolean(R.bool.show_test_settings) 796 || CellBroadcastReceiver.isTestingMode(context)) 797 && isTestAlertsAvailable; 798 } 799 isFeatureEnabled(Context context, String feature, boolean defaultValue)800 public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) { 801 CarrierConfigManager configManager = 802 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 803 804 if (configManager != null) { 805 PersistableBundle carrierConfig = configManager.getConfig(); 806 if (carrierConfig != null) { 807 return carrierConfig.getBoolean(feature, defaultValue); 808 } 809 } 810 811 return defaultValue; 812 } 813 814 /** 815 * Get the device resource based on SIM 816 * 817 * @param context Context 818 * @param subId Subscription index 819 * 820 * @return The resource 821 */ getResources(@onNull Context context, int subId)822 public static @NonNull Resources getResources(@NonNull Context context, int subId) { 823 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID 824 || !SubscriptionManager.isValidSubscriptionId(subId) 825 // based on the latest design, subId can be valid earlier than mcc mnc is known to 826 // telephony. check if sim is loaded to avoid caching the wrong resources. 827 || context.getSystemService(TelephonyManager.class).getSimApplicationState( 828 SubscriptionManager.getSlotIndex(subId)) != TelephonyManager.SIM_STATE_LOADED) { 829 return context.getResources(); 830 } 831 832 if (sResourcesCache.containsKey(subId)) { 833 return sResourcesCache.get(subId); 834 } 835 836 Resources res = SubscriptionManager.getResourcesForSubId(context, subId); 837 sResourcesCache.put(subId, res); 838 839 return res; 840 } 841 842 /** 843 * Get the resources using the default subscription ID. 844 * @param context Context 845 * @return the Resources for the default subscription ID, or if there is no default subscription 846 * from SubscriptionManager, the resources for the latest loaded SIM. 847 */ getResourcesForDefaultSubId(@onNull Context context)848 public static @NonNull Resources getResourcesForDefaultSubId(@NonNull Context context) { 849 return getResources(context, SubscriptionManager.getDefaultSubscriptionId()); 850 } 851 } 852